@x402x/extensions 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,1458 @@
1
+ import { defineChain, encodeAbiParameters, keccak256, encodePacked } from 'viem';
2
+ import * as allChains from 'viem/chains';
3
+
4
+ // src/types.ts
5
+ var SettlementExtraError = class extends Error {
6
+ constructor(message) {
7
+ super(message);
8
+ this.name = "SettlementExtraError";
9
+ }
10
+ };
11
+
12
+ // src/middleware-utils.ts
13
+ function computeRoutePatterns(routes) {
14
+ const normalizedRoutes = Object.fromEntries(
15
+ Object.entries(routes).map(([pattern, value]) => [
16
+ pattern,
17
+ typeof value === "string" || typeof value === "number" ? { price: value, network: "base-sepolia" } : value
18
+ ])
19
+ );
20
+ return Object.entries(normalizedRoutes).map(([pattern, routeConfig]) => {
21
+ const [verb, path] = pattern.includes(" ") ? pattern.split(/\s+/) : ["*", pattern];
22
+ if (!path) {
23
+ throw new Error(`Invalid route pattern: ${pattern}`);
24
+ }
25
+ return {
26
+ verb: verb.toUpperCase(),
27
+ pattern: new RegExp(
28
+ `^${path.replace(/\\/g, "\\\\").replace(/[$()+.?^{|}]/g, "\\$&").replace(/\*/g, ".*?").replace(/\[([^\]]+)\]/g, "[^/]+").replace(/\//g, "\\/")}$`,
29
+ "i"
30
+ ),
31
+ config: routeConfig
32
+ };
33
+ });
34
+ }
35
+ function findMatchingRoute(routePatterns, path, method) {
36
+ let normalizedPath;
37
+ try {
38
+ const pathWithoutQuery = path.split(/[?#]/)[0];
39
+ const decodedPath = decodeURIComponent(pathWithoutQuery);
40
+ normalizedPath = decodedPath.replace(/\\/g, "/").replace(/\/+/g, "/").replace(/(.+?)\/+$/, "$1");
41
+ } catch {
42
+ return void 0;
43
+ }
44
+ const matchingRoutes = routePatterns.filter(({ pattern, verb }) => {
45
+ const matchesPath = pattern.test(normalizedPath);
46
+ const upperMethod = method.toUpperCase();
47
+ const matchesVerb = verb === "*" || upperMethod === verb;
48
+ return matchesPath && matchesVerb;
49
+ });
50
+ return matchingRoutes[0];
51
+ }
52
+ function findMatchingPaymentRequirements(requirements, network) {
53
+ return requirements[0];
54
+ }
55
+ function toJsonSafe(value) {
56
+ if (value === null || value === void 0) {
57
+ return value;
58
+ }
59
+ if (typeof value === "bigint") {
60
+ return value.toString();
61
+ }
62
+ if (Array.isArray(value)) {
63
+ return value.map(toJsonSafe);
64
+ }
65
+ if (typeof value === "object") {
66
+ const result = {};
67
+ for (const [key, val] of Object.entries(value)) {
68
+ result[key] = toJsonSafe(val);
69
+ }
70
+ return result;
71
+ }
72
+ return value;
73
+ }
74
+ function calculateCommitment(params) {
75
+ return keccak256(
76
+ encodePacked(
77
+ [
78
+ "string",
79
+ // Protocol identifier
80
+ "uint256",
81
+ // Chain ID
82
+ "address",
83
+ // Hub address
84
+ "address",
85
+ // Token address
86
+ "address",
87
+ // From (payer)
88
+ "uint256",
89
+ // Value
90
+ "uint256",
91
+ // Valid after
92
+ "uint256",
93
+ // Valid before
94
+ "bytes32",
95
+ // Salt
96
+ "address",
97
+ // Pay to
98
+ "uint256",
99
+ // Facilitator fee
100
+ "address",
101
+ // Hook
102
+ "bytes32"
103
+ // keccak256(hookData)
104
+ ],
105
+ [
106
+ "X402/settle/v1",
107
+ BigInt(params.chainId),
108
+ params.hub,
109
+ params.asset,
110
+ params.from,
111
+ BigInt(params.value),
112
+ BigInt(params.validAfter),
113
+ BigInt(params.validBefore),
114
+ params.salt,
115
+ params.payTo,
116
+ BigInt(params.facilitatorFee),
117
+ params.hook,
118
+ keccak256(params.hookData)
119
+ ]
120
+ )
121
+ );
122
+ }
123
+ function generateSalt() {
124
+ const globalCrypto = typeof crypto !== "undefined" ? crypto : void 0;
125
+ if (globalCrypto?.getRandomValues) {
126
+ const bytes2 = new Uint8Array(32);
127
+ globalCrypto.getRandomValues(bytes2);
128
+ return `0x${Array.from(bytes2).map((b) => b.toString(16).padStart(2, "0")).join("")}`;
129
+ }
130
+ console.warn(
131
+ "[generateSalt] Using Math.random() fallback - consider upgrading to Node.js 15+ or use in browser"
132
+ );
133
+ const bytes = new Uint8Array(32);
134
+ for (let i = 0; i < 32; i++) {
135
+ bytes[i] = Math.floor(Math.random() * 256);
136
+ }
137
+ return `0x${Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("")}`;
138
+ }
139
+ function validateCommitmentParams(params) {
140
+ if (!isValidAddress(params.hub)) {
141
+ throw new Error("Invalid hub address");
142
+ }
143
+ if (!isValidAddress(params.asset)) {
144
+ throw new Error("Invalid asset address");
145
+ }
146
+ if (!isValidAddress(params.from)) {
147
+ throw new Error("Invalid from address");
148
+ }
149
+ if (!isValidAddress(params.payTo)) {
150
+ throw new Error("Invalid payTo address");
151
+ }
152
+ if (!isValidAddress(params.hook)) {
153
+ throw new Error("Invalid hook address");
154
+ }
155
+ try {
156
+ BigInt(params.value);
157
+ BigInt(params.validAfter);
158
+ BigInt(params.validBefore);
159
+ BigInt(params.facilitatorFee);
160
+ } catch (e) {
161
+ throw new Error("Invalid numeric parameter");
162
+ }
163
+ if (!isValidHex(params.salt) || params.salt.length !== 66) {
164
+ throw new Error("Invalid salt: must be bytes32 (0x + 64 hex chars)");
165
+ }
166
+ if (!isValidHex(params.hookData)) {
167
+ throw new Error("Invalid hookData: must be hex string");
168
+ }
169
+ }
170
+ function isValidAddress(address) {
171
+ return /^0x[0-9a-fA-F]{40}$/.test(address);
172
+ }
173
+ function isValidHex(hex) {
174
+ return /^0x[0-9a-fA-F]*$/.test(hex);
175
+ }
176
+
177
+ // src/network-utils.ts
178
+ var NETWORK_IDS = {
179
+ "base-sepolia": "eip155:84532",
180
+ "x-layer-testnet": "eip155:1952",
181
+ "skale-base-sepolia": "eip155:324705682",
182
+ "base": "eip155:8453",
183
+ "x-layer": "eip155:196",
184
+ "bsc-testnet": "eip155:97",
185
+ "bsc": "eip155:56"
186
+ };
187
+ var NETWORK_NAMES = {
188
+ "eip155:84532": "base-sepolia",
189
+ "eip155:1952": "x-layer-testnet",
190
+ "eip155:324705682": "skale-base-sepolia",
191
+ "eip155:8453": "base",
192
+ "eip155:196": "x-layer",
193
+ "eip155:97": "bsc-testnet",
194
+ "eip155:56": "bsc"
195
+ };
196
+ var DEFAULT_ASSETS = {
197
+ "eip155:84532": {
198
+ address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
199
+ decimals: 6,
200
+ eip712: {
201
+ name: "USDC",
202
+ version: "2"
203
+ }
204
+ },
205
+ "eip155:1952": {
206
+ address: "0xcb8bf24c6ce16ad21d707c9505421a17f2bec79d",
207
+ decimals: 6,
208
+ eip712: {
209
+ name: "USDC_TEST",
210
+ version: "2"
211
+ }
212
+ },
213
+ "eip155:324705682": {
214
+ address: "0x2e08028E3C4c2356572E096d8EF835cD5C6030bD",
215
+ decimals: 6,
216
+ eip712: {
217
+ name: "Bridged USDC (SKALE Bridge)",
218
+ version: "2"
219
+ }
220
+ },
221
+ "eip155:8453": {
222
+ address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
223
+ decimals: 6,
224
+ eip712: {
225
+ name: "USD Coin",
226
+ version: "2"
227
+ }
228
+ },
229
+ "eip155:196": {
230
+ address: "0x74b7f16337b8972027f6196a17a631ac6de26d22",
231
+ decimals: 6,
232
+ eip712: {
233
+ name: "USD Coin",
234
+ version: "2"
235
+ }
236
+ },
237
+ "eip155:97": {
238
+ address: "0xdac693b5f14e7ee5923a4830cd2f82ff178f5098",
239
+ decimals: 18,
240
+ eip712: {
241
+ name: "x402 Wrapped USDT",
242
+ version: "1"
243
+ }
244
+ },
245
+ "eip155:56": {
246
+ address: "0x2fDb94bAa9D664a1879BEe1f944F5F5d2dad4451",
247
+ decimals: 18,
248
+ eip712: {
249
+ name: "x402 Wrapped USDT",
250
+ version: "1"
251
+ }
252
+ }
253
+ };
254
+ function getNetworkId(networkName) {
255
+ const networkId = NETWORK_IDS[networkName];
256
+ if (!networkId) {
257
+ throw new Error(
258
+ `Unsupported network: ${networkName}. Supported networks: ${Object.keys(NETWORK_IDS).join(", ")}`
259
+ );
260
+ }
261
+ return networkId;
262
+ }
263
+ function getNetworkName(network) {
264
+ const networkName = NETWORK_NAMES[network];
265
+ if (!networkName) {
266
+ throw new Error(
267
+ `Unsupported network ID: ${network}. Supported network IDs: ${Object.keys(NETWORK_NAMES).join(", ")}`
268
+ );
269
+ }
270
+ return networkName;
271
+ }
272
+ function getDefaultAsset(network) {
273
+ const assetInfo = DEFAULT_ASSETS[network];
274
+ if (!assetInfo) {
275
+ throw new Error(`No default asset configured for network: ${network}`);
276
+ }
277
+ return assetInfo;
278
+ }
279
+ function parseMoneyToDecimal(money) {
280
+ if (typeof money === "number") {
281
+ return money;
282
+ }
283
+ const cleanMoney = money.replace(/^\$/, "").trim();
284
+ const amount = parseFloat(cleanMoney);
285
+ if (isNaN(amount)) {
286
+ throw new Error(`Invalid money format: ${money}`);
287
+ }
288
+ return amount;
289
+ }
290
+ function processPriceToAtomicAmount(price, network) {
291
+ try {
292
+ const amount = parseMoneyToDecimal(price);
293
+ const asset = getDefaultAsset(network);
294
+ const decimals = asset.decimals;
295
+ const [whole, fractional = "0"] = amount.toString().split(".");
296
+ const paddedFractional = fractional.padEnd(decimals, "0").slice(0, decimals);
297
+ const atomicAmount = BigInt(whole) * BigInt(10 ** decimals) + BigInt(paddedFractional);
298
+ return { amount: atomicAmount.toString() };
299
+ } catch (error) {
300
+ return {
301
+ error: error instanceof Error ? error.message : "Unknown error processing price"
302
+ };
303
+ }
304
+ }
305
+ var NETWORK_ALIASES_V1_TO_V2 = {
306
+ // V1 human-readable names -> V2 CAIP-2 canonical keys
307
+ "base-sepolia": "eip155:84532",
308
+ "x-layer-testnet": "eip155:1952",
309
+ "skale-base-sepolia": "eip155:324705682",
310
+ "base": "eip155:8453",
311
+ "x-layer": "eip155:196",
312
+ "bsc-testnet": "eip155:97",
313
+ "bsc": "eip155:56"
314
+ };
315
+ function getSupportedNetworkIds() {
316
+ return Object.keys(NETWORK_NAMES);
317
+ }
318
+ function getSupportedNetworksV2() {
319
+ return getSupportedNetworkIds();
320
+ }
321
+ function getNetworkAliasesV1ToV2() {
322
+ return { ...NETWORK_ALIASES_V1_TO_V2 };
323
+ }
324
+ function toCanonicalNetworkKey(network) {
325
+ if (network.startsWith("eip155:")) {
326
+ const canonicalNetwork2 = network;
327
+ if (canonicalNetwork2 in NETWORK_NAMES) {
328
+ return canonicalNetwork2;
329
+ }
330
+ throw new Error(
331
+ `Unsupported CAIP-2 network: ${network}. Supported networks: ${Object.keys(NETWORK_NAMES).join(", ")}`
332
+ );
333
+ }
334
+ const canonicalNetwork = NETWORK_ALIASES_V1_TO_V2[network];
335
+ if (!canonicalNetwork) {
336
+ throw new Error(
337
+ `Unsupported network: ${network}. Supported networks: ${Object.keys(NETWORK_ALIASES_V1_TO_V2).join(", ")}`
338
+ );
339
+ }
340
+ return canonicalNetwork;
341
+ }
342
+
343
+ // src/networks.ts
344
+ function getDefaultAssetConfig(network) {
345
+ const defaultAsset = getDefaultAsset(network);
346
+ return {
347
+ address: defaultAsset.address,
348
+ decimals: defaultAsset.decimals,
349
+ eip712: {
350
+ name: defaultAsset.eip712.name,
351
+ version: defaultAsset.eip712.version
352
+ }
353
+ };
354
+ }
355
+ var networks = {
356
+ "base-sepolia": {
357
+ chainId: parseInt(getNetworkId("base-sepolia").split(":")[1]),
358
+ name: "Base Sepolia",
359
+ type: "testnet",
360
+ addressExplorerBaseUrl: "https://sepolia.basescan.org/address/",
361
+ txExplorerBaseUrl: "https://sepolia.basescan.org/tx/",
362
+ settlementRouter: "0x817e4f0ee2fbdaac426f1178e149f7dc98873ecb",
363
+ defaultAsset: getDefaultAssetConfig(getNetworkId("base-sepolia")),
364
+ hooks: {
365
+ transfer: "0x4DE234059C6CcC94B8fE1eb1BD24804794083569"
366
+ },
367
+ demoHooks: {
368
+ nftMint: "0x261206558E6eEd104Cba4AD913b2Eec85D21108e",
369
+ randomNFT: "0x5756A67a33118F5Ad9840411f252E14d84Dd7c02",
370
+ reward: "0xf05cE06e7ee4ffCb67a509003DbD73A6d95Cc960",
371
+ rewardToken: "0xb6854e33BfD428d15B4f5398cFf8e84d4196FDA6"
372
+ },
373
+ metadata: {
374
+ gasModel: "eip1559",
375
+ nativeToken: "ETH"
376
+ }
377
+ },
378
+ "x-layer-testnet": {
379
+ chainId: parseInt(getNetworkId("x-layer-testnet").split(":")[1]),
380
+ name: "X Layer Testnet",
381
+ type: "testnet",
382
+ addressExplorerBaseUrl: "https://www.oklink.com/xlayer-test/address/",
383
+ txExplorerBaseUrl: "https://www.oklink.com/xlayer-test/tx/",
384
+ settlementRouter: "0xba9980fb08771e2fd10c17450f52d39bcb9ed576",
385
+ defaultAsset: getDefaultAssetConfig(getNetworkId("x-layer-testnet")),
386
+ hooks: {
387
+ transfer: "0xD4b98dd614c1Ea472fC4547a5d2B93f3D3637BEE"
388
+ },
389
+ demoHooks: {
390
+ nftMint: "0x468F666314b070338841422012AB2f6539bfcE48",
391
+ randomNFT: "0xBA931bB5B2F2DC5354aFAED1d3996B0c6e417518",
392
+ reward: "0xda8B270Ec442Ff797807b95604E3319e36Aad05d",
393
+ rewardToken: "0x348AFDE3B4B70dCb02053aF95588a4ab41e95FbC"
394
+ },
395
+ metadata: {
396
+ gasModel: "eip1559",
397
+ nativeToken: "OKB"
398
+ }
399
+ },
400
+ "skale-base-sepolia": {
401
+ chainId: parseInt(getNetworkId("skale-base-sepolia").split(":")[1]),
402
+ name: "SKALE Base Sepolia",
403
+ type: "testnet",
404
+ addressExplorerBaseUrl: "https://base-sepolia-testnet-explorer.skalenodes.com/address/",
405
+ txExplorerBaseUrl: "https://base-sepolia-testnet-explorer.skalenodes.com/tx/",
406
+ settlementRouter: "0x1Ae0E196dC18355aF3a19985faf67354213F833D",
407
+ defaultAsset: getDefaultAssetConfig(getNetworkId("skale-base-sepolia")),
408
+ hooks: {
409
+ transfer: "0x2f05fe5674aE756E25C26855258B4877E9e021Fd"
410
+ },
411
+ demoHooks: {
412
+ nftMint: "0x73fc659cd5494e69852be8d9d23fe05aab14b29b",
413
+ randomNFT: "0x081258287f692d61575387ee2a4075f34dd7aef7",
414
+ reward: "0xc20634ea518985901e32fbc1ba27fa673d37601a",
415
+ rewardToken: "0x9fc2c199170b039f093abcd54008038f0c0a31d6"
416
+ },
417
+ metadata: {
418
+ gasModel: "legacy",
419
+ nativeToken: "Credits"
420
+ }
421
+ },
422
+ "bsc-testnet": {
423
+ chainId: parseInt(getNetworkId("bsc-testnet").split(":")[1]),
424
+ name: "BSC Testnet",
425
+ type: "testnet",
426
+ addressExplorerBaseUrl: "https://testnet.bscscan.com/address/",
427
+ txExplorerBaseUrl: "https://testnet.bscscan.com/tx/",
428
+ settlementRouter: "0x1Ae0E196dC18355aF3a19985faf67354213F833D",
429
+ defaultAsset: getDefaultAssetConfig(getNetworkId("bsc-testnet")),
430
+ hooks: {
431
+ transfer: "0x2f05fe5674aE756E25C26855258B4877E9e021Fd"
432
+ },
433
+ demoHooks: {
434
+ nftMint: "0x73fc659Cd5494E69852bE8D9D23FE05Aab14b29B",
435
+ randomNFT: "0x081258287F692D61575387ee2a4075f34dd7Aef7",
436
+ reward: "0xC20634ea518985901e32Fbc1bA27fa673D37601A",
437
+ rewardToken: "0x9Fc2c199170B039f093ABCd54008038F0C0a31d6"
438
+ },
439
+ metadata: {
440
+ gasModel: "legacy",
441
+ nativeToken: "BNB"
442
+ }
443
+ },
444
+ // Mainnet configurations
445
+ base: {
446
+ chainId: parseInt(getNetworkId("base").split(":")[1]),
447
+ name: "Base Mainnet",
448
+ type: "mainnet",
449
+ addressExplorerBaseUrl: "https://basescan.org/address/",
450
+ txExplorerBaseUrl: "https://basescan.org/tx/",
451
+ settlementRouter: "0x73fc659Cd5494E69852bE8D9D23FE05Aab14b29B",
452
+ defaultAsset: getDefaultAssetConfig(getNetworkId("base")),
453
+ hooks: {
454
+ transfer: "0x081258287F692D61575387ee2a4075f34dd7Aef7"
455
+ },
456
+ demoHooks: {
457
+ nftMint: "0xC20634ea518985901e32Fbc1bA27fa673D37601A",
458
+ randomNFT: "0x9Fc2c199170B039f093ABCd54008038F0C0a31d6",
459
+ reward: "0x4B566FD5eFf76e3BdF20Ca5c3F2FA7cdbb3bD99A",
460
+ rewardToken: "0x12d41108f9F12064f792418C9BA0ACF6EdcE7790"
461
+ },
462
+ metadata: {
463
+ gasModel: "eip1559",
464
+ nativeToken: "ETH"
465
+ }
466
+ },
467
+ "x-layer": {
468
+ chainId: parseInt(getNetworkId("x-layer").split(":")[1]),
469
+ name: "X Layer Mainnet",
470
+ type: "mainnet",
471
+ addressExplorerBaseUrl: "https://www.oklink.com/xlayer/address/",
472
+ txExplorerBaseUrl: "https://www.oklink.com/xlayer/tx/",
473
+ settlementRouter: "0x73fc659Cd5494E69852bE8D9D23FE05Aab14b29B",
474
+ defaultAsset: getDefaultAssetConfig(getNetworkId("x-layer")),
475
+ hooks: {
476
+ transfer: "0x081258287F692D61575387ee2a4075f34dd7Aef7"
477
+ },
478
+ demoHooks: {
479
+ nftMint: "0xC20634ea518985901e32Fbc1bA27fa673D37601A",
480
+ randomNFT: "0x9Fc2c199170B039f093ABCd54008038F0C0a31d6",
481
+ reward: "0x4B566FD5eFf76e3BdF20Ca5c3F2FA7cdbb3bD99A",
482
+ rewardToken: "0x12d41108f9F12064f792418C9BA0ACF6EdcE7790"
483
+ },
484
+ metadata: {
485
+ gasModel: "eip1559",
486
+ nativeToken: "OKB"
487
+ }
488
+ },
489
+ bsc: {
490
+ chainId: parseInt(getNetworkId("bsc").split(":")[1]),
491
+ name: "BSC Mainnet",
492
+ type: "mainnet",
493
+ addressExplorerBaseUrl: "https://bscscan.com/address/",
494
+ txExplorerBaseUrl: "https://bscscan.com/tx/",
495
+ settlementRouter: "0x1Ae0E196dC18355aF3a19985faf67354213F833D",
496
+ defaultAsset: getDefaultAssetConfig(getNetworkId("bsc")),
497
+ hooks: {
498
+ transfer: "0x2f05fe5674aE756E25C26855258B4877E9e021Fd"
499
+ },
500
+ demoHooks: {
501
+ nftMint: "0x73fc659Cd5494E69852bE8D9D23FE05Aab14b29B",
502
+ randomNFT: "0x081258287F692D61575387ee2a4075f34dd7Aef7",
503
+ reward: "0xC20634ea518985901e32Fbc1bA27fa673D37601A",
504
+ rewardToken: "0x9Fc2c199170B039f093ABCd54008038F0C0a31d6"
505
+ },
506
+ metadata: {
507
+ gasModel: "legacy",
508
+ nativeToken: "BNB"
509
+ }
510
+ }
511
+ };
512
+ function getNetworkConfig(network) {
513
+ const config = networks[network];
514
+ if (!config) {
515
+ throw new Error(
516
+ `Unsupported network: ${network}. Supported networks: ${Object.keys(networks).join(", ")}`
517
+ );
518
+ }
519
+ return config;
520
+ }
521
+ function isNetworkSupported(network) {
522
+ return network in networks;
523
+ }
524
+ function getSupportedNetworkNames() {
525
+ return Object.keys(networks);
526
+ }
527
+ function getSupportedNetworks() {
528
+ return getSupportedNetworkNames();
529
+ }
530
+ var customChains = {
531
+ // X Layer Testnet
532
+ 1952: defineChain({
533
+ id: 1952,
534
+ name: "X Layer Testnet",
535
+ nativeCurrency: { name: "OKB", symbol: "OKB", decimals: 18 },
536
+ rpcUrls: {
537
+ default: { http: ["https://testrpc.xlayer.tech"] }
538
+ },
539
+ blockExplorers: {
540
+ default: { name: "OKLink", url: "https://www.oklink.com/xlayer-test" }
541
+ },
542
+ testnet: true
543
+ }),
544
+ // SKALE Nebula Testnet (Base Sepolia)
545
+ 324705682: defineChain({
546
+ id: 324705682,
547
+ name: "SKALE Nebula Testnet",
548
+ nativeCurrency: { name: "sFUEL", symbol: "sFUEL", decimals: 18 },
549
+ rpcUrls: {
550
+ default: {
551
+ http: ["https://testnet.skalenodes.com/v1/lanky-ill-funny-testnet"]
552
+ }
553
+ },
554
+ blockExplorers: {
555
+ default: {
556
+ name: "SKALE Explorer",
557
+ url: "https://lanky-ill-funny-testnet.explorer.testnet.skalenodes.com"
558
+ }
559
+ },
560
+ testnet: true
561
+ }),
562
+ // X Layer Mainnet
563
+ 196: defineChain({
564
+ id: 196,
565
+ name: "X Layer",
566
+ nativeCurrency: { name: "OKB", symbol: "OKB", decimals: 18 },
567
+ rpcUrls: {
568
+ default: { http: ["https://rpc.xlayer.tech"] }
569
+ },
570
+ blockExplorers: {
571
+ default: { name: "OKLink", url: "https://www.oklink.com/xlayer" }
572
+ },
573
+ testnet: false
574
+ })
575
+ };
576
+ function getChain(network) {
577
+ const networkId = getNetworkId(network);
578
+ const chainId = parseInt(networkId.split(":")[1]);
579
+ if (customChains[chainId]) {
580
+ return customChains[chainId];
581
+ }
582
+ const chain = Object.values(allChains).find((c) => c.id === chainId);
583
+ if (!chain) {
584
+ throw new Error(
585
+ `Unsupported network: ${network} (chain ID: ${chainId}). Please add custom chain definition in chains.ts`
586
+ );
587
+ }
588
+ return chain;
589
+ }
590
+ function getChainById(chainId) {
591
+ if (customChains[chainId]) {
592
+ return customChains[chainId];
593
+ }
594
+ const chain = Object.values(allChains).find((c) => c.id === chainId);
595
+ if (!chain) {
596
+ throw new Error(
597
+ `Unsupported chain ID: ${chainId}. Please add custom chain definition in chains.ts`
598
+ );
599
+ }
600
+ return chain;
601
+ }
602
+ function getCustomChains() {
603
+ return { ...customChains };
604
+ }
605
+ function isCustomChain(chainId) {
606
+ return chainId in customChains;
607
+ }
608
+ var TransferHook;
609
+ ((TransferHook2) => {
610
+ function encode(splits) {
611
+ if (!splits || splits.length === 0) {
612
+ return "0x";
613
+ }
614
+ let totalBips = 0;
615
+ for (const split of splits) {
616
+ if (!split.recipient || split.recipient === "0x0000000000000000000000000000000000000000") {
617
+ throw new Error(`Invalid recipient address: ${split.recipient}`);
618
+ }
619
+ if (split.bips <= 0) {
620
+ throw new Error(`Bips must be greater than 0, got: ${split.bips}`);
621
+ }
622
+ if (split.bips > 1e4) {
623
+ throw new Error(`Individual bips cannot exceed 10000, got: ${split.bips}`);
624
+ }
625
+ totalBips += split.bips;
626
+ }
627
+ if (totalBips > 1e4) {
628
+ throw new Error(`Total bips (${totalBips}) exceeds 10000 (100%)`);
629
+ }
630
+ return encodeAbiParameters(
631
+ [
632
+ {
633
+ type: "tuple[]",
634
+ name: "splits",
635
+ components: [
636
+ { name: "recipient", type: "address" },
637
+ { name: "bips", type: "uint16" }
638
+ ]
639
+ }
640
+ ],
641
+ [splits.map((s) => ({ recipient: s.recipient, bips: s.bips }))]
642
+ );
643
+ }
644
+ TransferHook2.encode = encode;
645
+ function getAddress(network) {
646
+ const config = getNetworkConfig(network);
647
+ return config.hooks.transfer;
648
+ }
649
+ TransferHook2.getAddress = getAddress;
650
+ })(TransferHook || (TransferHook = {}));
651
+ var NFTMintHook;
652
+ ((NFTMintHook2) => {
653
+ function getAddress(network) {
654
+ const config = getNetworkConfig(network);
655
+ if (!config.demoHooks?.nftMint) {
656
+ throw new Error(
657
+ `NFTMintHook not configured for network "${network}". Demo hooks are optional and may not be deployed on all networks.`
658
+ );
659
+ }
660
+ return config.demoHooks.nftMint;
661
+ }
662
+ NFTMintHook2.getAddress = getAddress;
663
+ function getNFTContractAddress(network) {
664
+ const config = getNetworkConfig(network);
665
+ if (!config.demoHooks?.randomNFT) {
666
+ throw new Error(
667
+ `RandomNFT contract not configured for network "${network}". Demo hooks are optional and may not be deployed on all networks.`
668
+ );
669
+ }
670
+ return config.demoHooks.randomNFT;
671
+ }
672
+ NFTMintHook2.getNFTContractAddress = getNFTContractAddress;
673
+ function encode(config) {
674
+ return encodeAbiParameters(
675
+ [
676
+ {
677
+ type: "tuple",
678
+ components: [{ name: "nftContract", type: "address" }]
679
+ }
680
+ ],
681
+ [
682
+ {
683
+ nftContract: config.nftContract
684
+ }
685
+ ]
686
+ );
687
+ }
688
+ NFTMintHook2.encode = encode;
689
+ })(NFTMintHook || (NFTMintHook = {}));
690
+ var RewardHook;
691
+ ((RewardHook2) => {
692
+ function getAddress(network) {
693
+ const config = getNetworkConfig(network);
694
+ if (!config.demoHooks?.reward) {
695
+ throw new Error(
696
+ `RewardHook not configured for network "${network}". Demo hooks are optional and may not be deployed on all networks.`
697
+ );
698
+ }
699
+ return config.demoHooks.reward;
700
+ }
701
+ RewardHook2.getAddress = getAddress;
702
+ function getTokenAddress(network) {
703
+ const config = getNetworkConfig(network);
704
+ if (!config.demoHooks?.rewardToken) {
705
+ throw new Error(
706
+ `Reward token not configured for network "${network}". Demo hooks are optional and may not be deployed on all networks.`
707
+ );
708
+ }
709
+ return config.demoHooks.rewardToken;
710
+ }
711
+ RewardHook2.getTokenAddress = getTokenAddress;
712
+ function encode(config) {
713
+ return encodeAbiParameters(
714
+ [
715
+ {
716
+ type: "tuple",
717
+ components: [{ name: "rewardToken", type: "address" }]
718
+ }
719
+ ],
720
+ [
721
+ {
722
+ rewardToken: config.rewardToken
723
+ }
724
+ ]
725
+ );
726
+ }
727
+ RewardHook2.encode = encode;
728
+ })(RewardHook || (RewardHook = {}));
729
+
730
+ // src/validation.ts
731
+ function isValidAddress2(address) {
732
+ return /^0x[a-fA-F0-9]{40}$/.test(address);
733
+ }
734
+ function isValidHex2(hex) {
735
+ return /^0x[a-fA-F0-9]*$/.test(hex) && hex.length % 2 === 0;
736
+ }
737
+ function isValid32ByteHex(hex) {
738
+ return /^0x[a-fA-F0-9]{64}$/.test(hex);
739
+ }
740
+ function isValidNumericString(value) {
741
+ return /^\d+$/.test(value);
742
+ }
743
+ function validateSettlementExtra(extra) {
744
+ if (!extra.settlementRouter) {
745
+ return { valid: false, error: "settlementRouter is required" };
746
+ }
747
+ if (!isValidAddress2(extra.settlementRouter)) {
748
+ return { valid: false, error: "settlementRouter must be a valid Ethereum address" };
749
+ }
750
+ if (!extra.payTo) {
751
+ return { valid: false, error: "payTo is required" };
752
+ }
753
+ if (!isValidAddress2(extra.payTo)) {
754
+ return { valid: false, error: "payTo must be a valid Ethereum address" };
755
+ }
756
+ if (extra.facilitatorFee === void 0 || extra.facilitatorFee === null) {
757
+ return { valid: false, error: "facilitatorFee is required" };
758
+ }
759
+ if (!isValidNumericString(extra.facilitatorFee)) {
760
+ return { valid: false, error: "facilitatorFee must be a non-negative numeric string" };
761
+ }
762
+ if (!extra.hook) {
763
+ return { valid: false, error: "hook is required" };
764
+ }
765
+ if (!isValidAddress2(extra.hook)) {
766
+ return { valid: false, error: "hook must be a valid Ethereum address" };
767
+ }
768
+ if (extra.hookData === void 0 || extra.hookData === null) {
769
+ return { valid: false, error: "hookData is required" };
770
+ }
771
+ if (!isValidHex2(extra.hookData)) {
772
+ return { valid: false, error: "hookData must be a valid hex string" };
773
+ }
774
+ if (!extra.name) {
775
+ return { valid: false, error: "name is required (EIP-712 domain name)" };
776
+ }
777
+ if (typeof extra.name !== "string" || extra.name.trim().length === 0) {
778
+ return { valid: false, error: "name must be a non-empty string" };
779
+ }
780
+ if (!extra.version) {
781
+ return { valid: false, error: "version is required (EIP-712 domain version)" };
782
+ }
783
+ if (typeof extra.version !== "string" || extra.version.trim().length === 0) {
784
+ return { valid: false, error: "version must be a non-empty string" };
785
+ }
786
+ if (!extra.salt) {
787
+ return { valid: false, error: "salt is required" };
788
+ }
789
+ if (!isValid32ByteHex(extra.salt)) {
790
+ return { valid: false, error: "salt must be a 32-byte hex string (0x followed by 64 hex characters)" };
791
+ }
792
+ return { valid: true };
793
+ }
794
+ function assertValidSettlementExtra(extra) {
795
+ const result = validateSettlementExtra(extra);
796
+ if (!result.valid) {
797
+ throw new SettlementExtraError(result.error || "Invalid settlement extra");
798
+ }
799
+ }
800
+
801
+ // src/utils.ts
802
+ function addSettlementExtra(requirements, params) {
803
+ const networkName = getNetworkName(requirements.network);
804
+ const config = getNetworkConfig(networkName);
805
+ const existingExtra = requirements.extra || {};
806
+ const name = existingExtra.name || config.defaultAsset.eip712.name;
807
+ const version = existingExtra.version || config.defaultAsset.eip712.version;
808
+ const extra = {
809
+ // Asset EIP-712 domain info (preserve existing if available)
810
+ name,
811
+ version,
812
+ // Settlement parameters
813
+ settlementRouter: config.settlementRouter,
814
+ salt: params.salt || generateSalt(),
815
+ payTo: params.payTo || requirements.payTo,
816
+ facilitatorFee: params.facilitatorFee || "0",
817
+ hook: params.hook,
818
+ hookData: params.hookData
819
+ };
820
+ assertValidSettlementExtra(extra);
821
+ return {
822
+ ...requirements,
823
+ // Override payTo to point to SettlementRouter
824
+ payTo: config.settlementRouter,
825
+ extra: {
826
+ ...requirements.extra,
827
+ ...extra
828
+ }
829
+ };
830
+ }
831
+
832
+ // src/extensions.ts
833
+ function createRouterSettlementExtension(params) {
834
+ const info = {
835
+ schemaVersion: 1
836
+ };
837
+ if (params?.description !== void 0) {
838
+ info.description = params.description;
839
+ }
840
+ if (params?.settlementRouter) info.settlementRouter = params.settlementRouter;
841
+ if (params?.hook) info.hook = params.hook;
842
+ if (params?.hookData) info.hookData = params.hookData;
843
+ if (params?.finalPayTo) info.finalPayTo = params.finalPayTo;
844
+ if (params?.facilitatorFee !== void 0) info.facilitatorFee = params.facilitatorFee;
845
+ let schema = params?.schema;
846
+ if (!schema && params?.settlementRouter) {
847
+ schema = {
848
+ type: "object",
849
+ properties: {
850
+ schemaVersion: { type: "number" },
851
+ description: { type: "string" },
852
+ salt: { type: "string", pattern: "^0x[a-fA-F0-9]{64}$" },
853
+ settlementRouter: { type: "string", pattern: "^0x[a-fA-F0-9]{40}$" },
854
+ hook: { type: "string", pattern: "^0x[a-fA-F0-9]{40}$" },
855
+ hookData: { type: "string", pattern: "^0x[a-fA-F0-9]*$" },
856
+ finalPayTo: { type: "string", pattern: "^0x[a-fA-F0-9]{40}$" },
857
+ facilitatorFee: { type: "string" }
858
+ },
859
+ // Salt is required in the final enriched version but not in the initial declaration
860
+ required: ["schemaVersion", "settlementRouter", "hook", "hookData", "finalPayTo"]
861
+ };
862
+ }
863
+ return {
864
+ info,
865
+ ...schema !== void 0 && { schema }
866
+ };
867
+ }
868
+ function getRouterSettlementExtensionKey() {
869
+ return "x402x-router-settlement";
870
+ }
871
+
872
+ // src/server-extension.ts
873
+ var ROUTER_SETTLEMENT_KEY = "x402x-router-settlement";
874
+ var routerSettlementServerExtension = {
875
+ key: ROUTER_SETTLEMENT_KEY,
876
+ enrichDeclaration: (declaration, transportContext) => {
877
+ const extension = declaration;
878
+ const salt = generateSalt();
879
+ const enriched = {
880
+ ...extension,
881
+ info: {
882
+ schemaVersion: 1,
883
+ ...extension.info || {},
884
+ // Add the generated salt to the info
885
+ salt
886
+ }
887
+ };
888
+ return enriched;
889
+ }
890
+ };
891
+ function registerRouterSettlement(server) {
892
+ server.registerExtension(routerSettlementServerExtension);
893
+ return server;
894
+ }
895
+ function createExtensionDeclaration(params) {
896
+ return {
897
+ [ROUTER_SETTLEMENT_KEY]: createRouterSettlementExtension(params)
898
+ };
899
+ }
900
+
901
+ // src/settlement-routes.ts
902
+ function createSettlementRouteConfig(baseConfig, settlementOptions) {
903
+ const acceptsArray = Array.isArray(baseConfig.accepts) ? baseConfig.accepts : [baseConfig.accepts];
904
+ const firstOption = acceptsArray[0];
905
+ const firstNetwork = firstOption.network;
906
+ const networkConfig = getNetworkConfig(firstNetwork);
907
+ if (!networkConfig) {
908
+ throw new Error(`Network configuration not found for: ${firstNetwork}`);
909
+ }
910
+ const hook = settlementOptions.hook || TransferHook.getAddress(firstNetwork);
911
+ const hookData = settlementOptions.hookData || TransferHook.encode();
912
+ const enhancedAccepts = acceptsArray.map((option) => {
913
+ const network = typeof option.network === "string" ? option.network : option.network;
914
+ const optionNetworkConfig = getNetworkConfig(network);
915
+ if (!optionNetworkConfig) {
916
+ throw new Error(`Network configuration not found for: ${network}`);
917
+ }
918
+ const enhancedOption = {
919
+ ...option,
920
+ // Override payTo to use settlementRouter as the immediate recipient
921
+ payTo: optionNetworkConfig.settlementRouter,
922
+ // Only include EIP-712 domain info in extra
923
+ extra: {
924
+ ...option.extra || {},
925
+ name: optionNetworkConfig.defaultAsset.eip712.name,
926
+ version: optionNetworkConfig.defaultAsset.eip712.version
927
+ }
928
+ };
929
+ return enhancedOption;
930
+ });
931
+ const extensions = {
932
+ ...baseConfig.extensions || {},
933
+ ...createExtensionDeclaration({
934
+ description: settlementOptions.description || "Router settlement with atomic fee distribution",
935
+ // Pass settlement parameters to be included in extension info
936
+ settlementRouter: networkConfig.settlementRouter,
937
+ hook,
938
+ hookData,
939
+ finalPayTo: settlementOptions.finalPayTo,
940
+ facilitatorFee: settlementOptions.facilitatorFee || "0"
941
+ })
942
+ };
943
+ return {
944
+ ...baseConfig,
945
+ accepts: enhancedAccepts.length === 1 ? enhancedAccepts[0] : enhancedAccepts,
946
+ extensions
947
+ };
948
+ }
949
+ function registerSettlementHooks(server, config = {}) {
950
+ const {
951
+ enableSaltExtraction = true,
952
+ validateSettlementParams = true
953
+ } = config;
954
+ if (enableSaltExtraction) {
955
+ server.onBeforeVerify(async (context) => {
956
+ const { paymentPayload, requirements } = context;
957
+ if (paymentPayload.extensions && "x402x-router-settlement" in paymentPayload.extensions) {
958
+ const extension = paymentPayload.extensions["x402x-router-settlement"];
959
+ if (extension?.info) {
960
+ if (!requirements.extra) {
961
+ requirements.extra = {};
962
+ }
963
+ const info = extension.info;
964
+ if (info.salt) requirements.extra.salt = info.salt;
965
+ if (info.settlementRouter) requirements.extra.settlementRouter = info.settlementRouter;
966
+ if (info.hook) requirements.extra.hook = info.hook;
967
+ if (info.hookData) requirements.extra.hookData = info.hookData;
968
+ if (info.finalPayTo) requirements.extra.payTo = info.finalPayTo;
969
+ if (info.facilitatorFee !== void 0) requirements.extra.facilitatorFee = info.facilitatorFee;
970
+ }
971
+ }
972
+ return void 0;
973
+ });
974
+ }
975
+ if (validateSettlementParams) {
976
+ server.onBeforeSettle(async (context) => {
977
+ const { paymentPayload, requirements } = context;
978
+ let settlementParams = {};
979
+ if (paymentPayload.extensions && "x402x-router-settlement" in paymentPayload.extensions) {
980
+ const extension = paymentPayload.extensions["x402x-router-settlement"];
981
+ if (extension?.info) {
982
+ settlementParams = extension.info;
983
+ }
984
+ }
985
+ if (!settlementParams.settlementRouter && requirements.extra) {
986
+ settlementParams = requirements.extra;
987
+ }
988
+ const requiredFields = ["settlementRouter", "hook", "hookData"];
989
+ const payToField = "finalPayTo" in settlementParams ? "finalPayTo" : "payTo";
990
+ const missingFields = requiredFields.filter((field) => !settlementParams[field]);
991
+ if (!settlementParams[payToField]) {
992
+ missingFields.push(payToField);
993
+ }
994
+ if (missingFields.length > 0) {
995
+ return {
996
+ abort: true,
997
+ reason: `Missing settlement parameters: ${missingFields.join(", ")}`
998
+ };
999
+ }
1000
+ return void 0;
1001
+ });
1002
+ }
1003
+ }
1004
+
1005
+ // src/helpers.ts
1006
+ function registerRouterSettlement2(server) {
1007
+ return registerRouterSettlement(server);
1008
+ }
1009
+ async function createX402xFacilitator(config) {
1010
+ try {
1011
+ const importFn = new Function("specifier", "return import(specifier)");
1012
+ const facilitatorModule = await importFn("@x402x/facilitator-sdk");
1013
+ return facilitatorModule.createRouterSettlementFacilitator(config);
1014
+ } catch (error) {
1015
+ throw new Error(
1016
+ "createX402xFacilitator requires @x402x/facilitator-sdk to be installed. Please install it using your package manager."
1017
+ );
1018
+ }
1019
+ }
1020
+ function withRouterSettlement(requirements, options) {
1021
+ if (!requirements.network) {
1022
+ throw new Error("Network is required in payment requirements");
1023
+ }
1024
+ if (!requirements.asset) {
1025
+ throw new Error("Asset is required in payment requirements");
1026
+ }
1027
+ const networkConfig = getNetworkConfig(requirements.network);
1028
+ if (!networkConfig) {
1029
+ throw new Error(`Network configuration not found for network: ${requirements.network}`);
1030
+ }
1031
+ const salt = options.salt || generateSalt();
1032
+ const settlementExtra = {
1033
+ settlementRouter: networkConfig.settlementRouter,
1034
+ salt,
1035
+ payTo: options.payTo,
1036
+ facilitatorFee: options.facilitatorFee,
1037
+ hook: options.hook,
1038
+ hookData: options.hookData,
1039
+ name: options.name || networkConfig.defaultAsset.eip712.name,
1040
+ version: options.version || networkConfig.defaultAsset.eip712.version
1041
+ };
1042
+ const extensionKey = getRouterSettlementExtensionKey();
1043
+ const extensionDeclaration = createRouterSettlementExtension({
1044
+ description: "Router settlement with atomic fee distribution"
1045
+ });
1046
+ const reqWithExtensions = requirements;
1047
+ return {
1048
+ ...requirements,
1049
+ extra: {
1050
+ ...reqWithExtensions.extra || {},
1051
+ ...settlementExtra
1052
+ },
1053
+ extensions: {
1054
+ ...reqWithExtensions.extensions || {},
1055
+ [extensionKey]: extensionDeclaration
1056
+ }
1057
+ };
1058
+ }
1059
+ function isRouterSettlement(requirements) {
1060
+ return !!(requirements.extra && "settlementRouter" in requirements.extra);
1061
+ }
1062
+
1063
+ // src/amount.ts
1064
+ var AmountError = class extends Error {
1065
+ constructor(message) {
1066
+ super(message);
1067
+ this.name = "AmountError";
1068
+ }
1069
+ };
1070
+ function parseDefaultAssetAmount(amount, network) {
1071
+ if (amount === null || amount === void 0 || amount === "") {
1072
+ throw new AmountError("Amount is required");
1073
+ }
1074
+ const result = processPriceToAtomicAmount(amount, network);
1075
+ if ("error" in result) {
1076
+ throw new AmountError(`Invalid amount format: ${result.error}`);
1077
+ }
1078
+ return result.amount;
1079
+ }
1080
+ function formatDefaultAssetAmount(amount, network) {
1081
+ const atomicAmount = BigInt(amount);
1082
+ if (atomicAmount < 0n) {
1083
+ throw new AmountError("Amount cannot be negative");
1084
+ }
1085
+ const asset = getDefaultAsset(network);
1086
+ const decimals = asset.decimals;
1087
+ const amountStr = atomicAmount.toString().padStart(decimals + 1, "0");
1088
+ const integerPart = amountStr.slice(0, -decimals) || "0";
1089
+ const decimalPart = amountStr.slice(-decimals);
1090
+ const trimmedDecimal = decimalPart.replace(/0+$/, "");
1091
+ if (trimmedDecimal) {
1092
+ return `${integerPart}.${trimmedDecimal}`;
1093
+ }
1094
+ return integerPart;
1095
+ }
1096
+
1097
+ // src/facilitator.ts
1098
+ function isSettlementMode(paymentRequirements) {
1099
+ return !!paymentRequirements.extra?.settlementRouter;
1100
+ }
1101
+ function parseSettlementExtra(extra) {
1102
+ if (!extra || typeof extra !== "object") {
1103
+ throw new SettlementExtraError("Missing or invalid extra field");
1104
+ }
1105
+ const e = extra;
1106
+ if (!e.settlementRouter || typeof e.settlementRouter !== "string") {
1107
+ throw new SettlementExtraError("Missing or invalid settlementRouter");
1108
+ }
1109
+ if (!e.salt || typeof e.salt !== "string") {
1110
+ throw new SettlementExtraError("Missing or invalid salt");
1111
+ }
1112
+ if (!e.payTo || typeof e.payTo !== "string") {
1113
+ throw new SettlementExtraError("Missing or invalid payTo");
1114
+ }
1115
+ if (!e.facilitatorFee || typeof e.facilitatorFee !== "string") {
1116
+ throw new SettlementExtraError("Missing or invalid facilitatorFee");
1117
+ }
1118
+ if (!e.hook || typeof e.hook !== "string") {
1119
+ throw new SettlementExtraError("Missing or invalid hook");
1120
+ }
1121
+ if (!e.hookData || typeof e.hookData !== "string") {
1122
+ throw new SettlementExtraError("Missing or invalid hookData");
1123
+ }
1124
+ return {
1125
+ settlementRouter: e.settlementRouter,
1126
+ salt: e.salt,
1127
+ payTo: e.payTo,
1128
+ facilitatorFee: e.facilitatorFee,
1129
+ hook: e.hook,
1130
+ hookData: e.hookData
1131
+ };
1132
+ }
1133
+ var FeeCache = class {
1134
+ constructor(ttlSeconds = 60) {
1135
+ this.cache = /* @__PURE__ */ new Map();
1136
+ this.ttlMs = ttlSeconds * 1e3;
1137
+ }
1138
+ getCacheKey(network, hook, hookData) {
1139
+ return `${network}:${hook}:${hookData || ""}`;
1140
+ }
1141
+ get(network, hook, hookData) {
1142
+ const key = this.getCacheKey(network, hook, hookData);
1143
+ const cached = this.cache.get(key);
1144
+ if (!cached) {
1145
+ return null;
1146
+ }
1147
+ if (Date.now() > cached.expiresAt) {
1148
+ this.cache.delete(key);
1149
+ return null;
1150
+ }
1151
+ return cached.result;
1152
+ }
1153
+ set(result) {
1154
+ const key = this.getCacheKey(result.network, result.hook, result.hookData);
1155
+ this.cache.set(key, {
1156
+ result,
1157
+ expiresAt: Date.now() + this.ttlMs
1158
+ });
1159
+ }
1160
+ clear() {
1161
+ this.cache.clear();
1162
+ }
1163
+ };
1164
+ var feeCache = new FeeCache(60);
1165
+ async function calculateFacilitatorFee(facilitatorUrl, network, hook, hookData, useCache = true) {
1166
+ if (useCache) {
1167
+ const cached = feeCache.get(network, hook, hookData);
1168
+ if (cached) {
1169
+ return cached;
1170
+ }
1171
+ }
1172
+ const baseUrl = facilitatorUrl.endsWith("/") ? facilitatorUrl.slice(0, -1) : facilitatorUrl;
1173
+ const params = new URLSearchParams({
1174
+ network,
1175
+ hook
1176
+ });
1177
+ if (hookData) {
1178
+ params.append("hookData", hookData);
1179
+ }
1180
+ const url = `${baseUrl}/calculate-fee?${params.toString()}`;
1181
+ try {
1182
+ const response = await fetch(url, {
1183
+ method: "GET",
1184
+ headers: {
1185
+ "Content-Type": "application/json"
1186
+ },
1187
+ // Add timeout
1188
+ signal: AbortSignal.timeout(3e3)
1189
+ });
1190
+ if (!response.ok) {
1191
+ const errorText = await response.text();
1192
+ throw new Error(
1193
+ `Facilitator fee calculation failed: ${response.status} ${response.statusText} - ${errorText}`
1194
+ );
1195
+ }
1196
+ const result = await response.json();
1197
+ if (!result.facilitatorFee || !result.network || !result.hook) {
1198
+ throw new Error("Invalid response from facilitator service");
1199
+ }
1200
+ if (useCache) {
1201
+ feeCache.set(result);
1202
+ }
1203
+ return result;
1204
+ } catch (error) {
1205
+ if (error instanceof Error) {
1206
+ throw new Error(`Failed to calculate facilitator fee: ${error.message}`);
1207
+ }
1208
+ throw error;
1209
+ }
1210
+ }
1211
+ function clearFeeCache() {
1212
+ feeCache.clear();
1213
+ }
1214
+ async function verify(facilitatorUrl, paymentPayload, paymentRequirements) {
1215
+ const baseUrl = facilitatorUrl.endsWith("/") ? facilitatorUrl.slice(0, -1) : facilitatorUrl;
1216
+ const url = `${baseUrl}/verify`;
1217
+ try {
1218
+ const response = await fetch(url, {
1219
+ method: "POST",
1220
+ headers: {
1221
+ "Content-Type": "application/json"
1222
+ },
1223
+ body: JSON.stringify({
1224
+ paymentPayload,
1225
+ paymentRequirements
1226
+ }),
1227
+ // Add timeout
1228
+ signal: AbortSignal.timeout(1e4)
1229
+ });
1230
+ if (!response.ok) {
1231
+ const errorText = await response.text();
1232
+ throw new Error(
1233
+ `Facilitator verify failed: ${response.status} ${response.statusText} - ${errorText}`
1234
+ );
1235
+ }
1236
+ const result = await response.json();
1237
+ if (typeof result.isValid !== "boolean") {
1238
+ throw new Error("Invalid response from facilitator: missing isValid field");
1239
+ }
1240
+ if (typeof result.payer !== "string") {
1241
+ throw new Error("Invalid response from facilitator: missing payer field");
1242
+ }
1243
+ return result;
1244
+ } catch (error) {
1245
+ if (error instanceof Error) {
1246
+ throw new Error(`Failed to verify with facilitator: ${error.message}`);
1247
+ }
1248
+ throw error;
1249
+ }
1250
+ }
1251
+ async function settle(facilitatorUrl, paymentPayload, paymentRequirements, timeout = 3e4) {
1252
+ const baseUrl = facilitatorUrl.endsWith("/") ? facilitatorUrl.slice(0, -1) : facilitatorUrl;
1253
+ const url = `${baseUrl}/settle`;
1254
+ const controller = new AbortController();
1255
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
1256
+ try {
1257
+ const response = await fetch(url, {
1258
+ method: "POST",
1259
+ headers: {
1260
+ "Content-Type": "application/json"
1261
+ },
1262
+ body: JSON.stringify({
1263
+ paymentPayload,
1264
+ paymentRequirements
1265
+ }),
1266
+ signal: controller.signal
1267
+ });
1268
+ clearTimeout(timeoutId);
1269
+ const result = await response.json();
1270
+ if (!response.ok) {
1271
+ throw new Error(
1272
+ result.error || result.message || `Facilitator settle failed: ${response.status}`
1273
+ );
1274
+ }
1275
+ if (typeof result.success !== "boolean") {
1276
+ throw new Error("Invalid response from facilitator: missing success field");
1277
+ }
1278
+ if (!result.success) {
1279
+ throw new Error(result.errorReason || "Settlement failed");
1280
+ }
1281
+ if (!result.transaction) {
1282
+ throw new Error("Invalid response from facilitator: missing transaction hash");
1283
+ }
1284
+ return {
1285
+ success: result.success,
1286
+ transaction: result.transaction,
1287
+ network: result.network || paymentRequirements.network,
1288
+ payer: result.payer || "",
1289
+ errorReason: result.errorReason
1290
+ };
1291
+ } catch (error) {
1292
+ clearTimeout(timeoutId);
1293
+ if (error instanceof Error) {
1294
+ if (error.name === "AbortError") {
1295
+ throw new Error(`Facilitator settle timed out after ${timeout}ms`);
1296
+ }
1297
+ throw new Error(`Failed to settle with facilitator: ${error.message}`);
1298
+ }
1299
+ throw error;
1300
+ }
1301
+ }
1302
+
1303
+ // src/abi.ts
1304
+ var SETTLEMENT_ROUTER_ABI = [
1305
+ {
1306
+ type: "function",
1307
+ name: "settleAndExecute",
1308
+ inputs: [
1309
+ { name: "token", type: "address" },
1310
+ { name: "from", type: "address" },
1311
+ { name: "value", type: "uint256" },
1312
+ { name: "validAfter", type: "uint256" },
1313
+ { name: "validBefore", type: "uint256" },
1314
+ { name: "nonce", type: "bytes32" },
1315
+ { name: "signature", type: "bytes" },
1316
+ { name: "salt", type: "bytes32" },
1317
+ { name: "payTo", type: "address" },
1318
+ { name: "facilitatorFee", type: "uint256" },
1319
+ { name: "hook", type: "address" },
1320
+ { name: "hookData", type: "bytes" }
1321
+ ],
1322
+ outputs: [],
1323
+ stateMutability: "nonpayable"
1324
+ },
1325
+ {
1326
+ type: "function",
1327
+ name: "calculateCommitment",
1328
+ inputs: [
1329
+ { name: "token", type: "address" },
1330
+ { name: "from", type: "address" },
1331
+ { name: "value", type: "uint256" },
1332
+ { name: "validAfter", type: "uint256" },
1333
+ { name: "validBefore", type: "uint256" },
1334
+ { name: "salt", type: "bytes32" },
1335
+ { name: "payTo", type: "address" },
1336
+ { name: "facilitatorFee", type: "uint256" },
1337
+ { name: "hook", type: "address" },
1338
+ { name: "hookData", type: "bytes" }
1339
+ ],
1340
+ outputs: [{ name: "", type: "bytes32" }],
1341
+ stateMutability: "view"
1342
+ },
1343
+ {
1344
+ type: "function",
1345
+ name: "calculateContextKey",
1346
+ inputs: [
1347
+ { name: "from", type: "address" },
1348
+ { name: "token", type: "address" },
1349
+ { name: "nonce", type: "bytes32" }
1350
+ ],
1351
+ outputs: [{ name: "", type: "bytes32" }],
1352
+ stateMutability: "pure"
1353
+ },
1354
+ {
1355
+ type: "function",
1356
+ name: "isSettled",
1357
+ inputs: [{ name: "contextKey", type: "bytes32" }],
1358
+ outputs: [{ name: "", type: "bool" }],
1359
+ stateMutability: "view"
1360
+ },
1361
+ {
1362
+ type: "function",
1363
+ name: "getPendingFees",
1364
+ inputs: [
1365
+ { name: "facilitator", type: "address" },
1366
+ { name: "token", type: "address" }
1367
+ ],
1368
+ outputs: [{ name: "", type: "uint256" }],
1369
+ stateMutability: "view"
1370
+ },
1371
+ {
1372
+ type: "function",
1373
+ name: "claimFees",
1374
+ inputs: [{ name: "tokens", type: "address[]" }],
1375
+ outputs: [],
1376
+ stateMutability: "nonpayable"
1377
+ }
1378
+ ];
1379
+
1380
+ // src/facilitator-types.ts
1381
+ var FacilitatorValidationError = class extends Error {
1382
+ constructor(message) {
1383
+ super(message);
1384
+ this.name = "FacilitatorValidationError";
1385
+ }
1386
+ };
1387
+ var SettlementRouterError = class extends Error {
1388
+ constructor(message, cause) {
1389
+ super(message);
1390
+ this.cause = cause;
1391
+ this.name = "SettlementRouterError";
1392
+ }
1393
+ };
1394
+
1395
+ // src/legacy-compat.ts
1396
+ var SupportedEVMNetworks = [
1397
+ "eip155:84532",
1398
+ // Base Sepolia
1399
+ "eip155:1444673419",
1400
+ // SKALE Base Sepolia
1401
+ "eip155:8453"
1402
+ // Base Mainnet
1403
+ ];
1404
+ var moneySchema = {
1405
+ parse: (value) => {
1406
+ if (typeof value === "string" || typeof value === "number") {
1407
+ return value;
1408
+ }
1409
+ throw new Error("Invalid money value");
1410
+ }
1411
+ };
1412
+ var settleResponseHeader = "X-Payment-Response";
1413
+ var evm = {
1414
+ /**
1415
+ * Check if a value is a valid EVM address
1416
+ */
1417
+ isAddress: (value) => {
1418
+ if (typeof value !== "string") return false;
1419
+ return /^0x[a-fA-F0-9]{40}$/.test(value);
1420
+ }
1421
+ };
1422
+ var exact = {
1423
+ name: "exact"
1424
+ // Additional scheme properties would go here
1425
+ };
1426
+ var ChainIdToNetwork = {
1427
+ 84532: "eip155:84532",
1428
+ // Base Sepolia
1429
+ 1444673419: "eip155:1444673419",
1430
+ // SKALE Base Sepolia
1431
+ 8453: "eip155:8453"
1432
+ // Base Mainnet
1433
+ };
1434
+ function isMultiNetworkSigner(signer) {
1435
+ return !!(signer && typeof signer === "object" && "signTransaction" in signer);
1436
+ }
1437
+ function isSvmSignerWallet(signer) {
1438
+ return !!(signer && typeof signer === "object" && "publicKey" in signer);
1439
+ }
1440
+ function createPaymentHeader(_requirements, _signer) {
1441
+ throw new Error("createPaymentHeader is not implemented in v2 - use x402Client instead");
1442
+ }
1443
+ function selectPaymentRequirements(_requirements, _selector) {
1444
+ throw new Error("selectPaymentRequirements is not implemented in v2 - use x402Client instead");
1445
+ }
1446
+ function decodeXPaymentResponse(_header) {
1447
+ throw new Error("decodeXPaymentResponse is not implemented in v2 - use x402HTTPClient instead");
1448
+ }
1449
+ function useFacilitator(_config) {
1450
+ throw new Error("useFacilitator is not implemented in v2 - use FacilitatorClient instead");
1451
+ }
1452
+ function createSigner(_config) {
1453
+ throw new Error("createSigner is not implemented in v2 - use appropriate v2 signer patterns");
1454
+ }
1455
+
1456
+ export { AmountError, ChainIdToNetwork, FacilitatorValidationError, NETWORK_ALIASES_V1_TO_V2, NFTMintHook, ROUTER_SETTLEMENT_KEY, RewardHook, SETTLEMENT_ROUTER_ABI, SettlementExtraError, SettlementRouterError, SupportedEVMNetworks, TransferHook, addSettlementExtra, assertValidSettlementExtra, calculateCommitment, calculateFacilitatorFee, clearFeeCache, computeRoutePatterns, createExtensionDeclaration, createPaymentHeader, createRouterSettlementExtension, createSettlementRouteConfig, createSigner, createX402xFacilitator, decodeXPaymentResponse, evm, exact, findMatchingPaymentRequirements, findMatchingRoute, formatDefaultAssetAmount, generateSalt, getChain, getChainById, getCustomChains, getDefaultAsset, getNetworkAliasesV1ToV2, getNetworkConfig, getNetworkId, getNetworkName, getRouterSettlementExtensionKey, getSupportedNetworkIds, getSupportedNetworkNames, getSupportedNetworks, getSupportedNetworksV2, isCustomChain, isMultiNetworkSigner, isNetworkSupported, isRouterSettlement, isSettlementMode, isSvmSignerWallet, isValid32ByteHex, isValidAddress2 as isValidAddress, isValidHex2 as isValidHex, isValidNumericString, moneySchema, networks, parseDefaultAssetAmount, parseSettlementExtra, processPriceToAtomicAmount, registerRouterSettlement2 as registerRouterSettlement, registerSettlementHooks, routerSettlementServerExtension, selectPaymentRequirements, settle, settleResponseHeader, toCanonicalNetworkKey, toJsonSafe, useFacilitator, validateCommitmentParams, validateSettlementExtra, verify, withRouterSettlement };
1457
+ //# sourceMappingURL=index.mjs.map
1458
+ //# sourceMappingURL=index.mjs.map