@armory-sh/base 0.2.28 → 0.2.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +304 -28
  2. package/dist/client-hooks-runtime.d.ts +9 -0
  3. package/dist/encoding/x402.d.ts +1 -1
  4. package/dist/errors.d.ts +10 -0
  5. package/dist/facilitator-capabilities.d.ts +9 -0
  6. package/dist/index.d.ts +30 -22
  7. package/dist/index.js +1198 -650
  8. package/dist/payment-client.d.ts +1 -1
  9. package/dist/payment-requirements.d.ts +35 -0
  10. package/dist/protocol.d.ts +33 -0
  11. package/dist/types/api.d.ts +1 -1
  12. package/dist/types/hooks.d.ts +17 -1
  13. package/dist/types/protocol.d.ts +1 -1
  14. package/dist/types/wallet.d.ts +24 -0
  15. package/dist/utils/base64.d.ts +4 -0
  16. package/dist/utils/x402.d.ts +1 -1
  17. package/dist/validation.d.ts +1 -1
  18. package/package.json +15 -2
  19. package/src/abi/erc20.ts +84 -0
  20. package/src/client-hooks-runtime.ts +153 -0
  21. package/src/data/tokens.ts +199 -0
  22. package/src/eip712.ts +108 -0
  23. package/src/encoding/x402.ts +205 -0
  24. package/src/encoding.ts +98 -0
  25. package/src/errors.ts +23 -0
  26. package/src/facilitator-capabilities.ts +125 -0
  27. package/src/index.ts +330 -0
  28. package/src/payment-client.ts +201 -0
  29. package/src/payment-requirements.ts +354 -0
  30. package/src/protocol.ts +57 -0
  31. package/src/types/api.ts +304 -0
  32. package/src/types/hooks.ts +85 -0
  33. package/src/types/networks.ts +175 -0
  34. package/src/types/protocol.ts +182 -0
  35. package/src/types/v2.ts +282 -0
  36. package/src/types/wallet.ts +30 -0
  37. package/src/types/x402.ts +151 -0
  38. package/src/utils/base64.ts +48 -0
  39. package/src/utils/routes.ts +240 -0
  40. package/src/utils/utils/index.ts +7 -0
  41. package/src/utils/utils/mock-facilitator.ts +184 -0
  42. package/src/utils/x402.ts +147 -0
  43. package/src/validation.ts +654 -0
package/dist/index.js CHANGED
@@ -1,14 +1,373 @@
1
1
  import { randomBytes } from 'crypto';
2
2
 
3
- // src/types/x402.ts
4
- var X402_VERSION = 2;
5
- var SCHEMES = ["exact"];
6
- function isPaymentPayload(obj) {
7
- return typeof obj === "object" && obj !== null && "x402Version" in obj && "accepted" in obj && "payload" in obj;
3
+ // src/abi/erc20.ts
4
+ var ERC20_ABI = [
5
+ {
6
+ type: "function",
7
+ name: "transferWithAuthorization",
8
+ stateMutability: "nonpayable",
9
+ inputs: [
10
+ { name: "from", type: "address" },
11
+ { name: "to", type: "address" },
12
+ { name: "amount", type: "uint256" },
13
+ { name: "validAfter", type: "uint256" },
14
+ { name: "expiry", type: "uint256" },
15
+ { name: "v", type: "uint8" },
16
+ { name: "r", type: "bytes32" },
17
+ { name: "s", type: "bytes32" }
18
+ ],
19
+ outputs: []
20
+ },
21
+ {
22
+ type: "function",
23
+ name: "receiveWithAuthorization",
24
+ stateMutability: "nonpayable",
25
+ inputs: [
26
+ { name: "from", type: "address" },
27
+ { name: "to", type: "address" },
28
+ { name: "amount", type: "uint256" },
29
+ { name: "validAfter", type: "uint256" },
30
+ { name: "expiry", type: "uint256" },
31
+ { name: "v", type: "uint8" },
32
+ { name: "r", type: "bytes32" },
33
+ { name: "s", type: "bytes32" }
34
+ ],
35
+ outputs: []
36
+ },
37
+ {
38
+ type: "function",
39
+ name: "balanceOf",
40
+ stateMutability: "view",
41
+ inputs: [{ name: "account", type: "address" }],
42
+ outputs: [{ name: "balance", type: "uint256" }]
43
+ },
44
+ {
45
+ type: "function",
46
+ name: "name",
47
+ stateMutability: "view",
48
+ inputs: [],
49
+ outputs: [{ name: "", type: "string" }]
50
+ },
51
+ {
52
+ type: "function",
53
+ name: "symbol",
54
+ stateMutability: "view",
55
+ inputs: [],
56
+ outputs: [{ name: "", type: "string" }]
57
+ }
58
+ ];
59
+
60
+ // src/client-hooks-runtime.ts
61
+ var notifyError = async (hooks, context) => {
62
+ if (!hooks?.length) {
63
+ return;
64
+ }
65
+ for (const hook of hooks) {
66
+ if (!hook.onError) {
67
+ continue;
68
+ }
69
+ await hook.onError(context);
70
+ }
71
+ };
72
+ var runOnPaymentRequiredHooks = async (hooks, context) => {
73
+ if (!hooks?.length) {
74
+ return;
75
+ }
76
+ for (const hook of hooks) {
77
+ if (!hook.onPaymentRequired) {
78
+ continue;
79
+ }
80
+ try {
81
+ await hook.onPaymentRequired(context);
82
+ } catch (error) {
83
+ await notifyError(hooks, { error, phase: "onPaymentRequired" });
84
+ throw error;
85
+ }
86
+ }
87
+ };
88
+ var selectRequirementWithHooks = async (hooks, context) => {
89
+ if (!context.accepts.length) {
90
+ throw new Error("No payment requirements found in accepts array");
91
+ }
92
+ let selected = context.accepts[0];
93
+ if (!hooks?.length) {
94
+ context.selectedRequirement = selected;
95
+ context.requirements = selected;
96
+ return selected;
97
+ }
98
+ for (const hook of hooks) {
99
+ if (!hook.selectRequirement) {
100
+ continue;
101
+ }
102
+ try {
103
+ const override = await hook.selectRequirement({
104
+ ...context,
105
+ selectedRequirement: selected,
106
+ requirements: selected
107
+ });
108
+ if (!override) {
109
+ continue;
110
+ }
111
+ const isValid = context.accepts.some((accept) => accept === override);
112
+ if (!isValid) {
113
+ throw new Error(
114
+ "Hook selectRequirement must return an item from accepts"
115
+ );
116
+ }
117
+ selected = override;
118
+ } catch (error) {
119
+ await notifyError(hooks, { error, phase: "selectRequirement" });
120
+ throw error;
121
+ }
122
+ }
123
+ context.selectedRequirement = selected;
124
+ context.requirements = selected;
125
+ return selected;
126
+ };
127
+ var runBeforeSignPaymentHooks = async (hooks, context) => {
128
+ if (!hooks?.length) {
129
+ return;
130
+ }
131
+ for (const hook of hooks) {
132
+ if (!hook.beforeSignPayment) {
133
+ continue;
134
+ }
135
+ try {
136
+ await hook.beforeSignPayment(context);
137
+ } catch (error) {
138
+ await notifyError(hooks, { error, phase: "beforeSignPayment" });
139
+ throw error;
140
+ }
141
+ }
142
+ };
143
+ var runAfterPaymentResponseHooks = async (hooks, context) => {
144
+ if (!hooks?.length) {
145
+ return;
146
+ }
147
+ for (const hook of hooks) {
148
+ if (!hook.afterPaymentResponse) {
149
+ continue;
150
+ }
151
+ try {
152
+ await hook.afterPaymentResponse(context);
153
+ } catch (error) {
154
+ await notifyError(hooks, { error, phase: "afterPaymentResponse" });
155
+ throw error;
156
+ }
157
+ }
158
+ };
159
+
160
+ // src/data/tokens.ts
161
+ var USDC_BASE = {
162
+ symbol: "USDC",
163
+ name: "USDC",
164
+ version: "2",
165
+ contractAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
166
+ chainId: 8453,
167
+ decimals: 6
168
+ };
169
+ var EURC_BASE = {
170
+ symbol: "EURC",
171
+ name: "EURC",
172
+ version: "2",
173
+ contractAddress: "0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42",
174
+ chainId: 8453,
175
+ decimals: 6
176
+ };
177
+ var USDC_BASE_SEPOLIA = {
178
+ symbol: "USDC",
179
+ name: "USDC",
180
+ version: "2",
181
+ contractAddress: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
182
+ chainId: 84532,
183
+ decimals: 6
184
+ };
185
+ var USDC_SKALE_BASE = {
186
+ symbol: "USDC",
187
+ name: "Bridged USDC (SKALE Bridge)",
188
+ version: "2",
189
+ contractAddress: "0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20",
190
+ chainId: 1187947933,
191
+ decimals: 6
192
+ };
193
+ var SKL_SKALE_BASE = {
194
+ symbol: "SKL",
195
+ name: "SKALE",
196
+ version: "1",
197
+ contractAddress: "0xE0595a049d02b7674572b0d59cd4880Db60EDC50",
198
+ chainId: 1187947933,
199
+ decimals: 18
200
+ };
201
+ var USDT_SKALE_BASE = {
202
+ symbol: "USDT",
203
+ name: "Tether USD",
204
+ version: "1",
205
+ contractAddress: "0x2bF5bF154b515EaA82C31a65ec11554fF5aF7fCA",
206
+ chainId: 1187947933,
207
+ decimals: 6
208
+ };
209
+ var WBTC_SKALE_BASE = {
210
+ symbol: "WBTC",
211
+ name: "Wrapped BTC",
212
+ version: "1",
213
+ contractAddress: "0x1aeeCFE5454c83B42D8A316246CAc9739E7f690e",
214
+ chainId: 1187947933,
215
+ decimals: 8
216
+ };
217
+ var WETH_SKALE_BASE = {
218
+ symbol: "WETH",
219
+ name: "Wrapped Ether",
220
+ version: "1",
221
+ contractAddress: "0x7bD39ABBd0Dd13103542cAe3276C7fA332bCA486",
222
+ chainId: 1187947933,
223
+ decimals: 18
224
+ };
225
+ var SKL_SKALE_BASE_SEPOLIA = {
226
+ symbol: "SKL",
227
+ name: "SKALE",
228
+ version: "1",
229
+ contractAddress: "0xaf2e0ff5b5f51553fdb34ce7f04a6c3201cee57b",
230
+ chainId: 324705682,
231
+ decimals: 18
232
+ };
233
+ var USDC_SKALE_BASE_SEPOLIA = {
234
+ symbol: "USDC",
235
+ name: "Bridged USDC (SKALE Bridge)",
236
+ version: "2",
237
+ contractAddress: "0x2e08028E3C4c2356572E096d8EF835cD5C6030bD",
238
+ chainId: 324705682,
239
+ decimals: 6
240
+ };
241
+ var USDT_SKALE_BASE_SEPOLIA = {
242
+ symbol: "USDT",
243
+ name: "Tether USD",
244
+ version: "1",
245
+ contractAddress: "0x3ca0a49f511c2c89c4dcbbf1731120d8919050bf",
246
+ chainId: 324705682,
247
+ decimals: 6
248
+ };
249
+ var WBTC_SKALE_BASE_SEPOLIA = {
250
+ symbol: "WBTC",
251
+ name: "Wrapped BTC",
252
+ version: "1",
253
+ contractAddress: "0x4512eacd4186b025186e1cf6cc0d89497c530e87",
254
+ chainId: 324705682,
255
+ decimals: 8
256
+ };
257
+ var WETH_SKALE_BASE_SEPOLIA = {
258
+ symbol: "WETH",
259
+ name: "Wrapped Ether",
260
+ version: "1",
261
+ contractAddress: "0xf94056bd7f6965db3757e1b145f200b7346b4fc0",
262
+ chainId: 324705682,
263
+ decimals: 18
264
+ };
265
+ var TOKENS = {
266
+ USDC_BASE,
267
+ USDC_BASE_SEPOLIA,
268
+ EURC_BASE,
269
+ USDC_SKALE_BASE,
270
+ USDT_SKALE_BASE,
271
+ WBTC_SKALE_BASE,
272
+ WETH_SKALE_BASE,
273
+ SKL_SKALE_BASE,
274
+ SKL_SKALE_BASE_SEPOLIA,
275
+ USDC_SKALE_BASE_SEPOLIA,
276
+ USDT_SKALE_BASE_SEPOLIA,
277
+ WBTC_SKALE_BASE_SEPOLIA,
278
+ WETH_SKALE_BASE_SEPOLIA
279
+ };
280
+ function getToken(chainId, contractAddress) {
281
+ const tokens = Object.values(TOKENS);
282
+ return tokens.find(
283
+ (t) => t.chainId === chainId && t.contractAddress.toLowerCase() === contractAddress.toLowerCase()
284
+ );
8
285
  }
9
- function isExactEvmPayload(obj) {
10
- return typeof obj === "object" && obj !== null && "signature" in obj && "authorization" in obj;
286
+ function getAllTokens() {
287
+ return Object.values(TOKENS);
288
+ }
289
+ function getTokensBySymbol(symbol) {
290
+ return getAllTokens().filter(
291
+ (t) => t.symbol.toUpperCase() === symbol.toUpperCase()
292
+ );
293
+ }
294
+ function getTokensByChain(chainId) {
295
+ return getAllTokens().filter((t) => t.chainId === chainId);
296
+ }
297
+ function getUSDCTokens() {
298
+ return getTokensBySymbol("USDC");
299
+ }
300
+ function getEURCTokens() {
301
+ return getTokensBySymbol("EURC");
302
+ }
303
+ function getSKLTokens() {
304
+ return getTokensBySymbol("SKL");
305
+ }
306
+ function getUSDTTokens() {
307
+ return getTokensBySymbol("USDT");
308
+ }
309
+ function getWBTCTokens() {
310
+ return getTokensBySymbol("WBTC");
11
311
  }
312
+ function getWETHTokens() {
313
+ return getTokensBySymbol("WETH");
314
+ }
315
+
316
+ // src/eip712.ts
317
+ var EIP712_TYPES = {
318
+ TransferWithAuthorization: [
319
+ { name: "from", type: "address" },
320
+ { name: "to", type: "address" },
321
+ { name: "value", type: "uint256" },
322
+ { name: "validAfter", type: "uint256" },
323
+ { name: "validBefore", type: "uint256" },
324
+ { name: "nonce", type: "bytes32" }
325
+ ]
326
+ };
327
+ var USDC_DOMAIN = {
328
+ NAME: "USD Coin",
329
+ VERSION: "2"
330
+ };
331
+ var createEIP712Domain = (chainId, contractAddress) => ({
332
+ name: USDC_DOMAIN.NAME,
333
+ version: USDC_DOMAIN.VERSION,
334
+ chainId,
335
+ verifyingContract: contractAddress
336
+ });
337
+ var createTransferWithAuthorization = (params) => ({
338
+ from: params.from,
339
+ to: params.to,
340
+ value: BigInt(params.value),
341
+ validAfter: BigInt(params.validAfter),
342
+ validBefore: BigInt(params.validBefore),
343
+ nonce: params.nonce
344
+ });
345
+ var isAddress = (value) => /^0x[a-fA-F0-9]{40}$/.test(value);
346
+ var isBytes32 = (value) => /^0x[a-fA-F0-9]{64}$/.test(value);
347
+ var validateTransferWithAuthorization = (message) => {
348
+ if (!isAddress(message.from))
349
+ throw new Error(`Invalid "from" address: ${message.from}`);
350
+ if (!isAddress(message.to))
351
+ throw new Error(`Invalid "to" address: ${message.to}`);
352
+ if (message.value < 0n)
353
+ throw new Error(`"value" must be non-negative: ${message.value}`);
354
+ if (message.validAfter < 0n)
355
+ throw new Error(`"validAfter" must be non-negative: ${message.validAfter}`);
356
+ if (message.validBefore < 0n)
357
+ throw new Error(
358
+ `"validBefore" must be non-negative: ${message.validBefore}`
359
+ );
360
+ if (message.validAfter >= message.validBefore) {
361
+ throw new Error(
362
+ `"validAfter" (${message.validAfter}) must be before "validBefore" (${message.validBefore})`
363
+ );
364
+ }
365
+ if (!isBytes32(message.nonce))
366
+ throw new Error(
367
+ `"nonce" must be a valid bytes32 hex string: ${message.nonce}`
368
+ );
369
+ return true;
370
+ };
12
371
 
13
372
  // src/types/v2.ts
14
373
  var V2_HEADERS = {
@@ -22,7 +381,7 @@ function isCAIP2ChainId(value) {
22
381
  function isCAIPAssetId(value) {
23
382
  return /^eip155:\d+\/erc20:0x[a-fA-F0-9]+$/.test(value);
24
383
  }
25
- function isAddress(value) {
384
+ function isAddress2(value) {
26
385
  return /^0x[a-fA-F0-9]{40}$/.test(value);
27
386
  }
28
387
  function isPaymentRequiredV2(obj) {
@@ -56,36 +415,98 @@ function combineSignature(v, r, s) {
56
415
  return `0x${rClean}${sClean}${vHex}`;
57
416
  }
58
417
 
59
- // src/encoding/x402.ts
60
- function safeBase64Encode(str) {
61
- return Buffer.from(str).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
418
+ // src/utils/base64.ts
419
+ var textEncoder = new TextEncoder();
420
+ var textDecoder = new TextDecoder();
421
+ function toBase64(bytes) {
422
+ if (typeof btoa === "function") {
423
+ let binary = "";
424
+ for (let index = 0; index < bytes.length; index += 1) {
425
+ binary += String.fromCharCode(bytes[index]);
426
+ }
427
+ return btoa(binary);
428
+ }
429
+ throw new Error("No base64 encoder available in this runtime");
62
430
  }
63
- function safeBase64Decode(str) {
64
- const padding = 4 - str.length % 4;
65
- if (padding !== 4) {
66
- str += "=".repeat(padding);
431
+ function fromBase64(base64) {
432
+ if (typeof atob === "function") {
433
+ const binary = atob(base64);
434
+ const bytes = new Uint8Array(binary.length);
435
+ for (let index = 0; index < binary.length; index += 1) {
436
+ bytes[index] = binary.charCodeAt(index);
437
+ }
438
+ return bytes;
67
439
  }
68
- str = str.replace(/-/g, "+").replace(/_/g, "/");
69
- return Buffer.from(str, "base64").toString("utf-8");
440
+ throw new Error("No base64 decoder available in this runtime");
441
+ }
442
+ function encodeUtf8ToBase64(value) {
443
+ const bytes = textEncoder.encode(value);
444
+ return toBase64(bytes);
445
+ }
446
+ function decodeBase64ToUtf8(value) {
447
+ const bytes = fromBase64(value);
448
+ return textDecoder.decode(bytes);
449
+ }
450
+ function toBase64Url(base64) {
451
+ return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
452
+ }
453
+ function normalizeBase64Url(value) {
454
+ return value.replace(/-/g, "+").replace(/_/g, "/").padEnd(Math.ceil(value.length / 4) * 4, "=");
455
+ }
456
+
457
+ // src/encoding.ts
458
+ function safeBase64Decode(str) {
459
+ return decodeBase64ToUtf8(normalizeBase64Url(str));
460
+ }
461
+ function safeBase64Encode(str) {
462
+ return toBase64Url(encodeUtf8ToBase64(str));
463
+ }
464
+ var base64JsonEncode = (data) => safeBase64Encode(JSON.stringify(data));
465
+ var base64JsonDecode = (encoded) => JSON.parse(safeBase64Decode(encoded));
466
+ var encodePaymentV2 = (payload) => base64JsonEncode(payload);
467
+ var decodePaymentV2 = (encoded) => base64JsonDecode(encoded);
468
+ var encodeSettlementV2 = (response) => base64JsonEncode(response);
469
+ var decodeSettlementV2 = (encoded) => base64JsonDecode(encoded);
470
+ var isPaymentV2 = (payload) => "x402Version" in payload && payload.x402Version === 2 && "accepted" in payload && "payload" in payload;
471
+ var isSettlementV2 = (response) => "success" in response && typeof response.success === "boolean" && "network" in response;
472
+
473
+ // src/types/x402.ts
474
+ var X402_VERSION = 2;
475
+ var SCHEMES = ["exact"];
476
+ function isPaymentPayload(obj) {
477
+ return typeof obj === "object" && obj !== null && "x402Version" in obj && "accepted" in obj && "payload" in obj;
478
+ }
479
+ function isExactEvmPayload(obj) {
480
+ return typeof obj === "object" && obj !== null && "signature" in obj && "authorization" in obj;
481
+ }
482
+
483
+ // src/encoding/x402.ts
484
+ function safeBase64Encode2(str) {
485
+ return toBase64Url(encodeUtf8ToBase64(str));
486
+ }
487
+ function safeBase64Decode2(str) {
488
+ return decodeBase64ToUtf8(normalizeBase64Url(str));
70
489
  }
71
490
  function encodePayment(payload) {
72
491
  if (!isPaymentPayload(payload)) {
73
492
  throw new Error("Invalid payment payload format");
74
493
  }
75
- const safePayload = JSON.parse(JSON.stringify(payload, (_, value) => {
76
- if (typeof value === "bigint") {
77
- return value.toString();
78
- }
79
- return value;
80
- }));
81
- return safeBase64Encode(JSON.stringify(safePayload));
494
+ const safePayload = JSON.parse(
495
+ JSON.stringify(payload, (_, value) => {
496
+ if (typeof value === "bigint") {
497
+ return value.toString();
498
+ }
499
+ return value;
500
+ })
501
+ );
502
+ return safeBase64Encode2(JSON.stringify(safePayload));
82
503
  }
83
504
  function decodePayment(encoded) {
84
505
  let parsed;
85
506
  try {
86
507
  parsed = JSON.parse(encoded);
87
508
  } catch {
88
- const decoded = safeBase64Decode(encoded);
509
+ const decoded = safeBase64Decode2(encoded);
89
510
  parsed = JSON.parse(decoded);
90
511
  }
91
512
  if (!isPaymentPayload(parsed)) {
@@ -94,30 +515,32 @@ function decodePayment(encoded) {
94
515
  return parsed;
95
516
  }
96
517
  function encodeSettlementResponse(response) {
97
- const safeResponse = JSON.parse(JSON.stringify(response, (_, value) => {
98
- if (typeof value === "bigint") {
99
- return value.toString();
100
- }
101
- return value;
102
- }));
103
- return safeBase64Encode(JSON.stringify(safeResponse));
518
+ const safeResponse = JSON.parse(
519
+ JSON.stringify(response, (_, value) => {
520
+ if (typeof value === "bigint") {
521
+ return value.toString();
522
+ }
523
+ return value;
524
+ })
525
+ );
526
+ return safeBase64Encode2(JSON.stringify(safeResponse));
104
527
  }
105
528
  function decodeSettlementResponse(encoded) {
106
529
  try {
107
530
  return JSON.parse(encoded);
108
531
  } catch {
109
- const decoded = safeBase64Decode(encoded);
532
+ const decoded = safeBase64Decode2(encoded);
110
533
  return JSON.parse(decoded);
111
534
  }
112
535
  }
113
536
  function encodeX402Response(response) {
114
- return safeBase64Encode(JSON.stringify(response));
537
+ return safeBase64Encode2(JSON.stringify(response));
115
538
  }
116
539
  function decodeX402Response(encoded) {
117
540
  try {
118
541
  return JSON.parse(encoded);
119
542
  } catch {
120
- const decoded = safeBase64Decode(encoded);
543
+ const decoded = safeBase64Decode2(encoded);
121
544
  return JSON.parse(decoded);
122
545
  }
123
546
  }
@@ -140,467 +563,345 @@ function createPaymentRequiredHeaders(requirements, options) {
140
563
  const accepts = Array.isArray(requirements) ? requirements : [requirements];
141
564
  const response = {
142
565
  x402Version: 2,
143
- error: options?.error ?? "Payment required",
144
- resource: options?.resource ?? { url: "", mimeType: "application/json" },
145
- accepts,
146
- extensions: options?.extensions ?? {}
147
- };
148
- return {
149
- [V2_HEADERS.PAYMENT_REQUIRED]: safeBase64Encode(JSON.stringify(response))
150
- };
151
- }
152
- function createSettlementHeaders(settlement) {
153
- return {
154
- [V2_HEADERS.PAYMENT_RESPONSE]: encodeSettlementResponse(settlement)
155
- };
156
- }
157
- function createNonce() {
158
- const bytes = randomBytes(32);
159
- return `0x${bytes.toString("hex")}`;
160
- }
161
- function toAtomicUnits(amount, decimals = 6) {
162
- const parts = amount.split(".");
163
- const whole = parts[0];
164
- const fractional = parts[1] || "";
165
- const paddedFractional = fractional.padEnd(decimals, "0").slice(0, decimals);
166
- return `${whole}${paddedFractional}`;
167
- }
168
- function fromAtomicUnits(amount, decimals = 6) {
169
- const value = BigInt(amount);
170
- const divisor = BigInt(10 ** decimals);
171
- const whole = (value / divisor).toString();
172
- const fractional = (value % divisor).toString().padStart(decimals, "0").replace(/0+$/, "");
173
- if (fractional.length === 0) {
174
- return whole;
175
- }
176
- return `${whole}.${fractional}`;
177
- }
178
- function caip2ToNetwork(caip2Id) {
179
- const match = caip2Id.match(/^eip155:(\d+)$/);
180
- if (!match) {
181
- return caip2Id;
182
- }
183
- const chainId = parseInt(match[1], 10);
184
- const chainIdToNetwork = {
185
- 1: "ethereum",
186
- 8453: "base",
187
- 84532: "base-sepolia",
188
- 137: "polygon",
189
- 42161: "arbitrum",
190
- 421614: "arbitrum-sepolia",
191
- 10: "optimism",
192
- 11155420: "optimism-sepolia",
193
- 11155111: "ethereum-sepolia"
194
- };
195
- return chainIdToNetwork[chainId] || caip2Id;
196
- }
197
- function networkToCaip2(network) {
198
- const networkToChainId = {
199
- ethereum: 1,
200
- base: 8453,
201
- "base-sepolia": 84532,
202
- polygon: 137,
203
- arbitrum: 42161,
204
- "arbitrum-sepolia": 421614,
205
- optimism: 10,
206
- "optimism-sepolia": 11155420,
207
- "ethereum-sepolia": 11155111
208
- };
209
- const chainId = networkToChainId[network];
210
- if (chainId) {
211
- return `eip155:${chainId}`;
212
- }
213
- if (network.startsWith("eip155:")) {
214
- return network;
215
- }
216
- return `eip155:0`;
217
- }
218
- function getCurrentTimestamp() {
219
- return Math.floor(Date.now() / 1e3);
220
- }
221
- function isValidAddress(address) {
222
- return /^0x[a-fA-F0-9]{40}$/.test(address);
223
- }
224
- function normalizeAddress(address) {
225
- return address.toLowerCase();
226
- }
227
-
228
- // src/types/protocol.ts
229
- function isX402V2Payload(obj) {
230
- return typeof obj === "object" && obj !== null && "x402Version" in obj && obj.x402Version === 2 && "accepted" in obj && "payload" in obj;
231
- }
232
- function isX402V2Requirements(obj) {
233
- return typeof obj === "object" && obj !== null && "scheme" in obj && obj.scheme === "exact" && "network" in obj && typeof obj.network === "string" && obj.network.startsWith("eip155:") && // CAIP-2 format
234
- "amount" in obj && "asset" in obj && "payTo" in obj && "maxTimeoutSeconds" in obj;
235
- }
236
- function isX402V2Settlement(obj) {
237
- return typeof obj === "object" && obj !== null && "success" in obj && typeof obj.success === "boolean" && "network" in obj && typeof obj.network === "string" && obj.network.startsWith("eip155:");
238
- }
239
- function isX402V2PaymentRequired(obj) {
240
- return typeof obj === "object" && obj !== null && "x402Version" in obj && obj.x402Version === 2 && "resource" in obj && "accepts" in obj;
241
- }
242
- var PAYMENT_SIGNATURE_HEADER = "PAYMENT-SIGNATURE";
243
- var PAYMENT_RESPONSE_HEADER = "PAYMENT-RESPONSE";
244
- var PAYMENT_REQUIRED_HEADER = "PAYMENT-REQUIRED";
245
- function isSettlementSuccessful(response) {
246
- return "success" in response ? response.success : false;
247
- }
248
- function getTxHash(response) {
249
- if ("transaction" in response) return response.transaction;
250
- return void 0;
251
- }
252
-
253
- // src/types/networks.ts
254
- var isEvmAddress = (value) => /^0x[a-fA-F0-9]{40}$/.test(value);
255
- var tokenRegistry = /* @__PURE__ */ new Map();
256
- var tokenKey = (chainId, contractAddress) => `${chainId}:${contractAddress.toLowerCase()}`;
257
- var NETWORKS = {
258
- ethereum: {
259
- name: "Ethereum Mainnet",
260
- chainId: 1,
261
- usdcAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
262
- rpcUrl: "https://eth.llamarpc.com",
263
- caip2Id: "eip155:1",
264
- caipAssetId: "eip155:1/erc20:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
265
- },
266
- base: {
267
- name: "Base Mainnet",
268
- chainId: 8453,
269
- usdcAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
270
- rpcUrl: "https://mainnet.base.org",
271
- caip2Id: "eip155:8453",
272
- caipAssetId: "eip155:8453/erc20:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
273
- },
274
- "base-sepolia": {
275
- name: "Base Sepolia",
276
- chainId: 84532,
277
- usdcAddress: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
278
- rpcUrl: "https://sepolia.base.org",
279
- caip2Id: "eip155:84532",
280
- caipAssetId: "eip155:84532/erc20:0x036CbD53842c5426634e7929541eC2318f3dCF7e"
281
- },
282
- "skale-base": {
283
- name: "SKALE Base",
284
- chainId: 1187947933,
285
- usdcAddress: "0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20",
286
- rpcUrl: "https://skale-base.skalenodes.com/v1/base",
287
- caip2Id: "eip155:1187947933",
288
- caipAssetId: "eip155:1187947933/erc20:0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20"
289
- },
290
- "skale-base-sepolia": {
291
- name: "SKALE Base Sepolia",
292
- chainId: 324705682,
293
- usdcAddress: "0x2e08028E3C4c2356572E096d8EF835cD5C6030bD",
294
- rpcUrl: "https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha",
295
- caip2Id: "eip155:324705682",
296
- caipAssetId: "eip155:324705682/erc20:0x2e08028E3C4c2356572E096d8EF835cD5C6030bD"
297
- },
298
- "ethereum-sepolia": {
299
- name: "Ethereum Sepolia",
300
- chainId: 11155111,
301
- usdcAddress: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
302
- rpcUrl: "https://rpc.sepolia.org",
303
- caip2Id: "eip155:11155111",
304
- caipAssetId: "eip155:11155111/erc20:0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238"
305
- }
306
- };
307
- var getNetworkConfig = (name) => NETWORKS[name];
308
- var getNetworkByChainId = (chainId) => Object.values(NETWORKS).find((c) => c.chainId === chainId);
309
- var getMainnets = () => Object.values(NETWORKS).filter((c) => !c.name.toLowerCase().includes("sepolia"));
310
- var getTestnets = () => Object.values(NETWORKS).filter((c) => c.name.toLowerCase().includes("sepolia"));
311
- var registerToken = (token) => {
312
- if (typeof token !== "object" || token === null) {
313
- throw new Error("Invalid token: must be an object");
314
- }
315
- const t = token;
316
- if (typeof t.symbol !== "string") {
317
- throw new Error("Invalid token: symbol must be a string");
318
- }
319
- if (typeof t.name !== "string") {
320
- throw new Error("Invalid token: name must be a string");
321
- }
322
- if (typeof t.version !== "string") {
323
- throw new Error("Invalid token: version must be a string");
324
- }
325
- if (typeof t.contractAddress !== "string" || !isEvmAddress(t.contractAddress)) {
326
- throw new Error("Invalid token: contractAddress must be a valid EVM address");
327
- }
328
- if (typeof t.chainId !== "number" || !Number.isInteger(t.chainId) || t.chainId <= 0) {
329
- throw new Error("Invalid token: chainId must be a positive integer");
330
- }
331
- if (t.decimals !== void 0 && (typeof t.decimals !== "number" || !Number.isInteger(t.decimals) || t.decimals < 0)) {
332
- throw new Error("Invalid token: decimals must be a non-negative integer");
333
- }
334
- const validated = {
335
- symbol: t.symbol,
336
- name: t.name,
337
- version: t.version,
338
- contractAddress: t.contractAddress,
339
- chainId: t.chainId,
340
- decimals: t.decimals
566
+ error: options?.error ?? "Payment required",
567
+ resource: options?.resource ?? { url: "", mimeType: "application/json" },
568
+ accepts,
569
+ extensions: options?.extensions ?? {}
341
570
  };
342
- tokenRegistry.set(tokenKey(validated.chainId, validated.contractAddress), validated);
343
- return validated;
344
- };
345
- var getCustomToken = (chainId, contractAddress) => tokenRegistry.get(tokenKey(chainId, contractAddress));
346
- var getAllCustomTokens = () => Array.from(tokenRegistry.values());
347
- var unregisterToken = (chainId, contractAddress) => tokenRegistry.delete(tokenKey(chainId, contractAddress));
348
- var isCustomToken = (chainId, contractAddress) => tokenRegistry.has(tokenKey(chainId, contractAddress));
571
+ return {
572
+ [V2_HEADERS.PAYMENT_REQUIRED]: safeBase64Encode2(JSON.stringify(response))
573
+ };
574
+ }
575
+ function createSettlementHeaders(settlement) {
576
+ return {
577
+ [V2_HEADERS.PAYMENT_RESPONSE]: encodeSettlementResponse(settlement)
578
+ };
579
+ }
349
580
 
350
- // src/data/tokens.ts
351
- var USDC_BASE = {
352
- symbol: "USDC",
353
- name: "USDC",
354
- version: "2",
355
- contractAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
356
- chainId: 8453,
357
- decimals: 6
358
- };
359
- var EURC_BASE = {
360
- symbol: "EURC",
361
- name: "EURC",
362
- version: "2",
363
- contractAddress: "0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42",
364
- chainId: 8453,
365
- decimals: 6
366
- };
367
- var USDC_BASE_SEPOLIA = {
368
- symbol: "USDC",
369
- name: "USDC",
370
- version: "2",
371
- contractAddress: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
372
- chainId: 84532,
373
- decimals: 6
374
- };
375
- var USDC_SKALE_BASE = {
376
- symbol: "USDC",
377
- name: "Bridged USDC (SKALE Bridge)",
378
- version: "2",
379
- contractAddress: "0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20",
380
- chainId: 1187947933,
381
- decimals: 6
382
- };
383
- var SKL_SKALE_BASE = {
384
- symbol: "SKL",
385
- name: "SKALE",
386
- version: "1",
387
- contractAddress: "0xE0595a049d02b7674572b0d59cd4880Db60EDC50",
388
- chainId: 1187947933,
389
- decimals: 18
390
- };
391
- var USDT_SKALE_BASE = {
392
- symbol: "USDT",
393
- name: "Tether USD",
394
- version: "1",
395
- contractAddress: "0x2bF5bF154b515EaA82C31a65ec11554fF5aF7fCA",
396
- chainId: 1187947933,
397
- decimals: 6
398
- };
399
- var WBTC_SKALE_BASE = {
400
- symbol: "WBTC",
401
- name: "Wrapped BTC",
402
- version: "1",
403
- contractAddress: "0x1aeeCFE5454c83B42D8A316246CAc9739E7f690e",
404
- chainId: 1187947933,
405
- decimals: 8
406
- };
407
- var WETH_SKALE_BASE = {
408
- symbol: "WETH",
409
- name: "Wrapped Ether",
410
- version: "1",
411
- contractAddress: "0x7bD39ABBd0Dd13103542cAe3276C7fA332bCA486",
412
- chainId: 1187947933,
413
- decimals: 18
414
- };
415
- var SKL_SKALE_BASE_SEPOLIA = {
416
- symbol: "SKL",
417
- name: "SKALE",
418
- version: "1",
419
- contractAddress: "0xaf2e0ff5b5f51553fdb34ce7f04a6c3201cee57b",
420
- chainId: 324705682,
421
- decimals: 18
422
- };
423
- var USDC_SKALE_BASE_SEPOLIA = {
424
- symbol: "USDC",
425
- name: "Bridged USDC (SKALE Bridge)",
426
- version: "2",
427
- contractAddress: "0x2e08028E3C4c2356572E096d8EF835cD5C6030bD",
428
- chainId: 324705682,
429
- decimals: 6
430
- };
431
- var USDT_SKALE_BASE_SEPOLIA = {
432
- symbol: "USDT",
433
- name: "Tether USD",
434
- version: "1",
435
- contractAddress: "0x3ca0a49f511c2c89c4dcbbf1731120d8919050bf",
436
- chainId: 324705682,
437
- decimals: 6
438
- };
439
- var WBTC_SKALE_BASE_SEPOLIA = {
440
- symbol: "WBTC",
441
- name: "Wrapped BTC",
442
- version: "1",
443
- contractAddress: "0x4512eacd4186b025186e1cf6cc0d89497c530e87",
444
- chainId: 324705682,
445
- decimals: 8
581
+ // src/errors.ts
582
+ var X402ClientError = class extends Error {
583
+ cause;
584
+ constructor(message, cause) {
585
+ super(message);
586
+ this.name = "X402ClientError";
587
+ this.cause = cause;
588
+ }
446
589
  };
447
- var WETH_SKALE_BASE_SEPOLIA = {
448
- symbol: "WETH",
449
- name: "Wrapped Ether",
450
- version: "1",
451
- contractAddress: "0xf94056bd7f6965db3757e1b145f200b7346b4fc0",
452
- chainId: 324705682,
453
- decimals: 18
590
+ var SigningError = class extends X402ClientError {
591
+ constructor(message, cause) {
592
+ super(`Signing failed: ${message}`, cause);
593
+ this.name = "SigningError";
594
+ }
454
595
  };
455
- var TOKENS = {
456
- USDC_BASE,
457
- USDC_BASE_SEPOLIA,
458
- EURC_BASE,
459
- USDC_SKALE_BASE,
460
- USDT_SKALE_BASE,
461
- WBTC_SKALE_BASE,
462
- WETH_SKALE_BASE,
463
- SKL_SKALE_BASE,
464
- SKL_SKALE_BASE_SEPOLIA,
465
- USDC_SKALE_BASE_SEPOLIA,
466
- USDT_SKALE_BASE_SEPOLIA,
467
- WBTC_SKALE_BASE_SEPOLIA,
468
- WETH_SKALE_BASE_SEPOLIA
596
+ var PaymentException = class extends X402ClientError {
597
+ constructor(message, cause) {
598
+ super(`Payment failed: ${message}`, cause);
599
+ this.name = "PaymentException";
600
+ }
469
601
  };
470
- function getToken(chainId, contractAddress) {
471
- const tokens = Object.values(TOKENS);
472
- return tokens.find(
473
- (t) => t.chainId === chainId && t.contractAddress.toLowerCase() === contractAddress.toLowerCase()
474
- );
475
- }
476
- function getAllTokens() {
477
- return Object.values(TOKENS);
602
+
603
+ // src/payment-client.ts
604
+ var DEFAULT_FACILITATOR_URL = "https://facilitator.payai.network";
605
+ function toJsonSafe(data) {
606
+ function convert(value) {
607
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
608
+ return Object.fromEntries(
609
+ Object.entries(value).map(([key, val]) => [key, convert(val)])
610
+ );
611
+ }
612
+ if (Array.isArray(value)) {
613
+ return value.map(convert);
614
+ }
615
+ if (typeof value === "bigint") {
616
+ return value.toString();
617
+ }
618
+ return value;
619
+ }
620
+ return convert(data);
478
621
  }
479
- function getTokensBySymbol(symbol) {
480
- return getAllTokens().filter((t) => t.symbol.toUpperCase() === symbol.toUpperCase());
622
+ function resolveUrl(config) {
623
+ return config?.url ?? DEFAULT_FACILITATOR_URL;
481
624
  }
482
- function getTokensByChain(chainId) {
483
- return getAllTokens().filter((t) => t.chainId === chainId);
625
+ async function resolveHeaders(config) {
626
+ const base = { "Content-Type": "application/json" };
627
+ if (!config?.createHeaders) return base;
628
+ const extra = await config.createHeaders();
629
+ return { ...base, ...extra };
484
630
  }
485
- function getUSDCTokens() {
486
- return getTokensBySymbol("USDC");
631
+ async function verifyPayment(payload, requirements, config) {
632
+ const url = resolveUrl(config);
633
+ const headers = await resolveHeaders(config);
634
+ const response = await fetch(`${url}/verify`, {
635
+ method: "POST",
636
+ headers,
637
+ body: JSON.stringify({
638
+ paymentPayload: toJsonSafe(payload),
639
+ paymentRequirements: toJsonSafe(requirements)
640
+ })
641
+ });
642
+ if (response.status !== 200) {
643
+ const text = await response.text().catch(() => response.statusText);
644
+ throw new Error(`Facilitator verify failed: ${response.status} ${text}`);
645
+ }
646
+ return await response.json();
487
647
  }
488
- function getEURCTokens() {
489
- return getTokensBySymbol("EURC");
648
+ async function settlePayment(payload, requirements, config) {
649
+ const url = resolveUrl(config);
650
+ const headers = await resolveHeaders(config);
651
+ const response = await fetch(`${url}/settle`, {
652
+ method: "POST",
653
+ headers,
654
+ body: JSON.stringify({
655
+ paymentPayload: toJsonSafe(payload),
656
+ paymentRequirements: toJsonSafe(requirements)
657
+ })
658
+ });
659
+ if (response.status !== 200) {
660
+ const text = await response.text().catch(() => response.statusText);
661
+ throw new Error(`Facilitator settle failed: ${response.status} ${text}`);
662
+ }
663
+ return await response.json();
490
664
  }
491
- function getSKLTokens() {
492
- return getTokensBySymbol("SKL");
665
+ async function getSupported(config) {
666
+ const url = resolveUrl(config);
667
+ const headers = await resolveHeaders(config);
668
+ const response = await fetch(`${url}/supported`, {
669
+ method: "GET",
670
+ headers
671
+ });
672
+ if (response.status !== 200) {
673
+ throw new Error(`Facilitator supported failed: ${response.statusText}`);
674
+ }
675
+ return await response.json();
493
676
  }
494
- function getUSDTTokens() {
495
- return getTokensBySymbol("USDT");
677
+ function isCompactV2Payload(payload) {
678
+ if (typeof payload !== "object" || payload === null) return false;
679
+ const record = payload;
680
+ return typeof record.x402Version === "number" && "payload" in record && !("accepted" in record);
496
681
  }
497
- function getWBTCTokens() {
498
- return getTokensBySymbol("WBTC");
682
+ function decodePayloadHeader(headerValue, defaults) {
683
+ if (headerValue.startsWith("{")) {
684
+ const parsed = JSON.parse(headerValue);
685
+ if (isPaymentPayload(parsed)) return parsed;
686
+ if (isCompactV2Payload(parsed)) {
687
+ const compact = parsed;
688
+ if (!defaults?.accepted) {
689
+ throw new Error(
690
+ "Invalid payment payload: missing 'accepted' field and no defaults provided"
691
+ );
692
+ }
693
+ return {
694
+ x402Version: 2,
695
+ accepted: defaults.accepted,
696
+ payload: compact.payload
697
+ };
698
+ }
699
+ throw new Error("Invalid payment payload: unrecognized format");
700
+ }
701
+ const normalized = headerValue.replace(/-/g, "+").replace(/_/g, "/").padEnd(Math.ceil(headerValue.length / 4) * 4, "=");
702
+ try {
703
+ const decoded = JSON.parse(decodeBase64ToUtf8(normalized));
704
+ if (isPaymentPayload(decoded)) return decoded;
705
+ if (isCompactV2Payload(decoded)) {
706
+ const compact = decoded;
707
+ if (!defaults?.accepted) {
708
+ throw new Error(
709
+ "Invalid payment payload: missing 'accepted' field and no defaults provided"
710
+ );
711
+ }
712
+ return {
713
+ x402Version: 2,
714
+ accepted: defaults.accepted,
715
+ payload: compact.payload
716
+ };
717
+ }
718
+ throw new Error("Invalid payment payload: unrecognized format");
719
+ } catch {
720
+ throw new Error("Invalid payment payload: failed to decode");
721
+ }
499
722
  }
500
- function getWETHTokens() {
501
- return getTokensBySymbol("WETH");
723
+ function extractPayerAddress(payload) {
724
+ if (isExactEvmPayload(payload.payload)) {
725
+ return payload.payload.authorization.from;
726
+ }
727
+ throw new Error("Unable to extract payer address from payload");
502
728
  }
503
729
 
504
- // src/abi/erc20.ts
505
- var ERC20_ABI = [
506
- {
507
- type: "function",
508
- name: "transferWithAuthorization",
509
- stateMutability: "nonpayable",
510
- inputs: [
511
- { name: "from", type: "address" },
512
- { name: "to", type: "address" },
513
- { name: "amount", type: "uint256" },
514
- { name: "validAfter", type: "uint256" },
515
- { name: "expiry", type: "uint256" },
516
- { name: "v", type: "uint8" },
517
- { name: "r", type: "bytes32" },
518
- { name: "s", type: "bytes32" }
519
- ],
520
- outputs: []
730
+ // src/types/networks.ts
731
+ var isEvmAddress = (value) => /^0x[a-fA-F0-9]{40}$/.test(value);
732
+ var tokenRegistry = /* @__PURE__ */ new Map();
733
+ var tokenKey = (chainId, contractAddress) => `${chainId}:${contractAddress.toLowerCase()}`;
734
+ var NETWORKS = {
735
+ ethereum: {
736
+ name: "Ethereum Mainnet",
737
+ chainId: 1,
738
+ usdcAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
739
+ rpcUrl: "https://eth.llamarpc.com",
740
+ caip2Id: "eip155:1",
741
+ caipAssetId: "eip155:1/erc20:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
521
742
  },
522
- {
523
- type: "function",
524
- name: "receiveWithAuthorization",
525
- stateMutability: "nonpayable",
526
- inputs: [
527
- { name: "from", type: "address" },
528
- { name: "to", type: "address" },
529
- { name: "amount", type: "uint256" },
530
- { name: "validAfter", type: "uint256" },
531
- { name: "expiry", type: "uint256" },
532
- { name: "v", type: "uint8" },
533
- { name: "r", type: "bytes32" },
534
- { name: "s", type: "bytes32" }
535
- ],
536
- outputs: []
743
+ base: {
744
+ name: "Base Mainnet",
745
+ chainId: 8453,
746
+ usdcAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
747
+ rpcUrl: "https://mainnet.base.org",
748
+ caip2Id: "eip155:8453",
749
+ caipAssetId: "eip155:8453/erc20:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
537
750
  },
538
- {
539
- type: "function",
540
- name: "balanceOf",
541
- stateMutability: "view",
542
- inputs: [{ name: "account", type: "address" }],
543
- outputs: [{ name: "balance", type: "uint256" }]
751
+ "base-sepolia": {
752
+ name: "Base Sepolia",
753
+ chainId: 84532,
754
+ usdcAddress: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
755
+ rpcUrl: "https://sepolia.base.org",
756
+ caip2Id: "eip155:84532",
757
+ caipAssetId: "eip155:84532/erc20:0x036CbD53842c5426634e7929541eC2318f3dCF7e"
544
758
  },
545
- {
546
- type: "function",
547
- name: "name",
548
- stateMutability: "view",
549
- inputs: [],
550
- outputs: [{ name: "", type: "string" }]
759
+ "skale-base": {
760
+ name: "SKALE Base",
761
+ chainId: 1187947933,
762
+ usdcAddress: "0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20",
763
+ rpcUrl: "https://skale-base.skalenodes.com/v1/base",
764
+ caip2Id: "eip155:1187947933",
765
+ caipAssetId: "eip155:1187947933/erc20:0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20"
551
766
  },
552
- {
553
- type: "function",
554
- name: "symbol",
555
- stateMutability: "view",
556
- inputs: [],
557
- outputs: [{ name: "", type: "string" }]
767
+ "skale-base-sepolia": {
768
+ name: "SKALE Base Sepolia",
769
+ chainId: 324705682,
770
+ usdcAddress: "0x2e08028E3C4c2356572E096d8EF835cD5C6030bD",
771
+ rpcUrl: "https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha",
772
+ caip2Id: "eip155:324705682",
773
+ caipAssetId: "eip155:324705682/erc20:0x2e08028E3C4c2356572E096d8EF835cD5C6030bD"
774
+ },
775
+ "ethereum-sepolia": {
776
+ name: "Ethereum Sepolia",
777
+ chainId: 11155111,
778
+ usdcAddress: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
779
+ rpcUrl: "https://rpc.sepolia.org",
780
+ caip2Id: "eip155:11155111",
781
+ caipAssetId: "eip155:11155111/erc20:0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238"
558
782
  }
559
- ];
560
-
561
- // src/eip712.ts
562
- var EIP712_TYPES = {
563
- TransferWithAuthorization: [
564
- { name: "from", type: "address" },
565
- { name: "to", type: "address" },
566
- { name: "value", type: "uint256" },
567
- { name: "validAfter", type: "uint256" },
568
- { name: "validBefore", type: "uint256" },
569
- { name: "nonce", type: "bytes32" }
570
- ]
571
- };
572
- var USDC_DOMAIN = {
573
- NAME: "USD Coin",
574
- VERSION: "2"
575
783
  };
576
- var createEIP712Domain = (chainId, contractAddress) => ({
577
- name: USDC_DOMAIN.NAME,
578
- version: USDC_DOMAIN.VERSION,
579
- chainId,
580
- verifyingContract: contractAddress
581
- });
582
- var createTransferWithAuthorization = (params) => ({
583
- from: params.from,
584
- to: params.to,
585
- value: BigInt(params.value),
586
- validAfter: BigInt(params.validAfter),
587
- validBefore: BigInt(params.validBefore),
588
- nonce: params.nonce
589
- });
590
- var isAddress2 = (value) => /^0x[a-fA-F0-9]{40}$/.test(value);
591
- var isBytes32 = (value) => /^0x[a-fA-F0-9]{64}$/.test(value);
592
- var validateTransferWithAuthorization = (message) => {
593
- if (!isAddress2(message.from)) throw new Error(`Invalid "from" address: ${message.from}`);
594
- if (!isAddress2(message.to)) throw new Error(`Invalid "to" address: ${message.to}`);
595
- if (message.value < 0n) throw new Error(`"value" must be non-negative: ${message.value}`);
596
- if (message.validAfter < 0n) throw new Error(`"validAfter" must be non-negative: ${message.validAfter}`);
597
- if (message.validBefore < 0n) throw new Error(`"validBefore" must be non-negative: ${message.validBefore}`);
598
- if (message.validAfter >= message.validBefore) {
599
- throw new Error(`"validAfter" (${message.validAfter}) must be before "validBefore" (${message.validBefore})`);
784
+ var getNetworkConfig = (name) => NETWORKS[name];
785
+ var getNetworkByChainId = (chainId) => Object.values(NETWORKS).find((c) => c.chainId === chainId);
786
+ var getMainnets = () => Object.values(NETWORKS).filter(
787
+ (c) => !c.name.toLowerCase().includes("sepolia")
788
+ );
789
+ var getTestnets = () => Object.values(NETWORKS).filter(
790
+ (c) => c.name.toLowerCase().includes("sepolia")
791
+ );
792
+ var registerToken = (token) => {
793
+ if (typeof token !== "object" || token === null) {
794
+ throw new Error("Invalid token: must be an object");
600
795
  }
601
- if (!isBytes32(message.nonce)) throw new Error(`"nonce" must be a valid bytes32 hex string: ${message.nonce}`);
602
- return true;
796
+ const t = token;
797
+ if (typeof t.symbol !== "string") {
798
+ throw new Error("Invalid token: symbol must be a string");
799
+ }
800
+ if (typeof t.name !== "string") {
801
+ throw new Error("Invalid token: name must be a string");
802
+ }
803
+ if (typeof t.version !== "string") {
804
+ throw new Error("Invalid token: version must be a string");
805
+ }
806
+ if (typeof t.contractAddress !== "string" || !isEvmAddress(t.contractAddress)) {
807
+ throw new Error(
808
+ "Invalid token: contractAddress must be a valid EVM address"
809
+ );
810
+ }
811
+ if (typeof t.chainId !== "number" || !Number.isInteger(t.chainId) || t.chainId <= 0) {
812
+ throw new Error("Invalid token: chainId must be a positive integer");
813
+ }
814
+ if (t.decimals !== void 0 && (typeof t.decimals !== "number" || !Number.isInteger(t.decimals) || t.decimals < 0)) {
815
+ throw new Error("Invalid token: decimals must be a non-negative integer");
816
+ }
817
+ const validated = {
818
+ symbol: t.symbol,
819
+ name: t.name,
820
+ version: t.version,
821
+ contractAddress: t.contractAddress,
822
+ chainId: t.chainId,
823
+ decimals: t.decimals
824
+ };
825
+ tokenRegistry.set(
826
+ tokenKey(validated.chainId, validated.contractAddress),
827
+ validated
828
+ );
829
+ return validated;
603
830
  };
831
+ var getCustomToken = (chainId, contractAddress) => tokenRegistry.get(tokenKey(chainId, contractAddress));
832
+ var getAllCustomTokens = () => Array.from(tokenRegistry.values());
833
+ var unregisterToken = (chainId, contractAddress) => tokenRegistry.delete(tokenKey(chainId, contractAddress));
834
+ var isCustomToken = (chainId, contractAddress) => tokenRegistry.has(tokenKey(chainId, contractAddress));
835
+ function createNonce() {
836
+ const bytes = randomBytes(32);
837
+ return `0x${bytes.toString("hex")}`;
838
+ }
839
+ function toAtomicUnits(amount, decimals = 6) {
840
+ const parts = amount.split(".");
841
+ const whole = parts[0];
842
+ const fractional = parts[1] || "";
843
+ const paddedFractional = fractional.padEnd(decimals, "0").slice(0, decimals);
844
+ return `${whole}${paddedFractional}`;
845
+ }
846
+ function fromAtomicUnits(amount, decimals = 6) {
847
+ const value = BigInt(amount);
848
+ const divisor = BigInt(10 ** decimals);
849
+ const whole = (value / divisor).toString();
850
+ const fractional = (value % divisor).toString().padStart(decimals, "0").replace(/0+$/, "");
851
+ if (fractional.length === 0) {
852
+ return whole;
853
+ }
854
+ return `${whole}.${fractional}`;
855
+ }
856
+ function caip2ToNetwork(caip2Id) {
857
+ const match = caip2Id.match(/^eip155:(\d+)$/);
858
+ if (!match) {
859
+ return caip2Id;
860
+ }
861
+ const chainId = parseInt(match[1], 10);
862
+ const chainIdToNetwork = {
863
+ 1: "ethereum",
864
+ 8453: "base",
865
+ 84532: "base-sepolia",
866
+ 137: "polygon",
867
+ 42161: "arbitrum",
868
+ 421614: "arbitrum-sepolia",
869
+ 10: "optimism",
870
+ 11155420: "optimism-sepolia",
871
+ 11155111: "ethereum-sepolia"
872
+ };
873
+ return chainIdToNetwork[chainId] || caip2Id;
874
+ }
875
+ function networkToCaip2(network) {
876
+ const networkToChainId = {
877
+ ethereum: 1,
878
+ base: 8453,
879
+ "base-sepolia": 84532,
880
+ polygon: 137,
881
+ arbitrum: 42161,
882
+ "arbitrum-sepolia": 421614,
883
+ optimism: 10,
884
+ "optimism-sepolia": 11155420,
885
+ "ethereum-sepolia": 11155111
886
+ };
887
+ const chainId = networkToChainId[network];
888
+ if (chainId) {
889
+ return `eip155:${chainId}`;
890
+ }
891
+ if (network.startsWith("eip155:")) {
892
+ return network;
893
+ }
894
+ return `eip155:0`;
895
+ }
896
+ function getCurrentTimestamp() {
897
+ return Math.floor(Date.now() / 1e3);
898
+ }
899
+ function isValidAddress(address) {
900
+ return /^0x[a-fA-F0-9]{40}$/.test(address);
901
+ }
902
+ function normalizeAddress(address) {
903
+ return address.toLowerCase();
904
+ }
604
905
 
605
906
  // src/validation.ts
606
907
  var isEvmAddress2 = (value) => /^0x[a-fA-F0-9]{40}$/.test(value);
@@ -614,7 +915,9 @@ var resolveNetwork = (input) => {
614
915
  if (typeof input === "object" && input !== null && "chainId" in input) {
615
916
  const config = input;
616
917
  if (!config.chainId || !config.usdcAddress || !config.caip2Id) {
617
- return createError("INVALID_CAIP_FORMAT", "Invalid network config", { value: config });
918
+ return createError("INVALID_CAIP_FORMAT", "Invalid network config", {
919
+ value: config
920
+ });
618
921
  }
619
922
  return {
620
923
  input,
@@ -626,11 +929,10 @@ var resolveNetwork = (input) => {
626
929
  const config = getNetworkByChainId(input);
627
930
  if (!config) {
628
931
  const validChainIds = Object.values(NETWORKS).map((n) => n.chainId);
629
- return createError(
630
- "UNKNOWN_NETWORK",
631
- `Unknown chain ID: ${input}`,
632
- { value: input, validOptions: validChainIds.map(String) }
633
- );
932
+ return createError("UNKNOWN_NETWORK", `Unknown chain ID: ${input}`, {
933
+ value: input,
934
+ validOptions: validChainIds.map(String)
935
+ });
634
936
  }
635
937
  return {
636
938
  input,
@@ -641,13 +943,21 @@ var resolveNetwork = (input) => {
641
943
  if (typeof input === "string") {
642
944
  if (input.startsWith("eip155:")) {
643
945
  const parts = input.split(":");
644
- if (parts.length !== 2 || isNaN(Number(parts[1]))) {
645
- return createError("INVALID_CAIP_FORMAT", `Invalid CAIP-2 format: ${input}`, { value: input });
946
+ if (parts.length !== 2 || Number.isNaN(Number(parts[1]))) {
947
+ return createError(
948
+ "INVALID_CAIP_FORMAT",
949
+ `Invalid CAIP-2 format: ${input}`,
950
+ { value: input }
951
+ );
646
952
  }
647
953
  const chainId = Number(parts[1]);
648
954
  const config2 = getNetworkByChainId(chainId);
649
955
  if (!config2) {
650
- return createError("UNKNOWN_NETWORK", `Unknown CAIP-2 network: ${input}`, { value: input });
956
+ return createError(
957
+ "UNKNOWN_NETWORK",
958
+ `Unknown CAIP-2 network: ${input}`,
959
+ { value: input }
960
+ );
651
961
  }
652
962
  return {
653
963
  input,
@@ -659,11 +969,10 @@ var resolveNetwork = (input) => {
659
969
  const config = getNetworkConfig(normalizedName);
660
970
  if (!config) {
661
971
  const validNames = Object.keys(NETWORKS);
662
- return createError(
663
- "UNKNOWN_NETWORK",
664
- `Unknown network: "${input}"`,
665
- { value: input, validOptions: validNames }
666
- );
972
+ return createError("UNKNOWN_NETWORK", `Unknown network: "${input}"`, {
973
+ value: input,
974
+ validOptions: validNames
975
+ });
667
976
  }
668
977
  return {
669
978
  input,
@@ -671,7 +980,11 @@ var resolveNetwork = (input) => {
671
980
  caip2: config.caip2Id
672
981
  };
673
982
  }
674
- return createError("UNKNOWN_NETWORK", `Invalid network identifier type: ${typeof input}`, { value: input });
983
+ return createError(
984
+ "UNKNOWN_NETWORK",
985
+ `Invalid network identifier type: ${typeof input}`,
986
+ { value: input }
987
+ );
675
988
  };
676
989
  var getAvailableNetworks = () => Object.keys(NETWORKS);
677
990
  var normalizeTokenSymbol = (symbol) => symbol.toUpperCase();
@@ -679,7 +992,9 @@ var resolveToken = (input, network) => {
679
992
  if (typeof input === "object" && input !== null && "contractAddress" in input) {
680
993
  const config = input;
681
994
  if (!config.chainId || !config.contractAddress || !config.symbol) {
682
- return createError("VALIDATION_FAILED", "Invalid token config", { value: config });
995
+ return createError("VALIDATION_FAILED", "Invalid token config", {
996
+ value: config
997
+ });
683
998
  }
684
999
  if (network && config.chainId !== network.config.chainId) {
685
1000
  return createError(
@@ -704,7 +1019,10 @@ var resolveToken = (input, network) => {
704
1019
  if (isEvmAddress2(input)) {
705
1020
  const contractAddress = input;
706
1021
  if (network) {
707
- const customToken = getCustomToken(network.config.chainId, contractAddress);
1022
+ const customToken = getCustomToken(
1023
+ network.config.chainId,
1024
+ contractAddress
1025
+ );
708
1026
  const config = customToken || {
709
1027
  symbol: "CUSTOM",
710
1028
  name: "Custom Token",
@@ -747,7 +1065,11 @@ var resolveToken = (input, network) => {
747
1065
  if (input.includes("/erc20:")) {
748
1066
  const parts = input.split("/");
749
1067
  if (parts.length !== 2) {
750
- return createError("INVALID_CAIP_FORMAT", `Invalid CAIP Asset ID format: ${input}`, { value: input });
1068
+ return createError(
1069
+ "INVALID_CAIP_FORMAT",
1070
+ `Invalid CAIP Asset ID format: ${input}`,
1071
+ { value: input }
1072
+ );
751
1073
  }
752
1074
  const chainId = Number(parts[0].split(":")[1]);
753
1075
  const contractAddress = parts[1].split(":")[1];
@@ -789,7 +1111,7 @@ var resolveToken = (input, network) => {
789
1111
  input,
790
1112
  config: {
791
1113
  symbol: normalizedSymbol,
792
- name: network.config.name + " " + normalizedSymbol,
1114
+ name: `${network.config.name} ${normalizedSymbol}`,
793
1115
  version: "2",
794
1116
  chainId: network.config.chainId,
795
1117
  contractAddress: network.config.usdcAddress,
@@ -800,7 +1122,9 @@ var resolveToken = (input, network) => {
800
1122
  };
801
1123
  }
802
1124
  const customTokens = getAllCustomTokens();
803
- const matchingToken = customTokens.find((t) => t.symbol?.toUpperCase() === normalizedSymbol);
1125
+ const matchingToken = customTokens.find(
1126
+ (t) => t.symbol?.toUpperCase() === normalizedSymbol
1127
+ );
804
1128
  if (matchingToken) {
805
1129
  const tokenNetwork = resolveNetwork(matchingToken.chainId);
806
1130
  if ("code" in tokenNetwork) {
@@ -831,7 +1155,11 @@ var resolveToken = (input, network) => {
831
1155
  network: baseNetwork
832
1156
  };
833
1157
  }
834
- return createError("UNKNOWN_TOKEN", `Invalid token identifier type: ${typeof input}`, { value: input });
1158
+ return createError(
1159
+ "UNKNOWN_TOKEN",
1160
+ `Invalid token identifier type: ${typeof input}`,
1161
+ { value: input }
1162
+ );
835
1163
  };
836
1164
  var getAvailableTokens = () => {
837
1165
  const customTokens = getAllCustomTokens();
@@ -842,7 +1170,11 @@ var resolveFacilitator = (input, supportedNetworks, supportedTokens) => {
842
1170
  try {
843
1171
  new URL(input.url);
844
1172
  } catch {
845
- return createError("VALIDATION_FAILED", `Invalid facilitator URL: ${input.url}`, { value: input.url });
1173
+ return createError(
1174
+ "VALIDATION_FAILED",
1175
+ `Invalid facilitator URL: ${input.url}`,
1176
+ { value: input.url }
1177
+ );
846
1178
  }
847
1179
  const networks = [];
848
1180
  if (input.networks) {
@@ -900,12 +1232,18 @@ var checkFacilitatorSupport = (facilitator, network, token) => {
900
1232
  (t) => t.config.contractAddress.toLowerCase() === token.config.contractAddress.toLowerCase() && t.network.config.chainId === token.network.config.chainId
901
1233
  );
902
1234
  if (!tokenSupported) {
903
- const supportedTokens = facilitator.tokens.map((t) => `${t.config.symbol} (${t.network.config.name})`);
1235
+ const supportedTokens = facilitator.tokens.map(
1236
+ (t) => `${t.config.symbol} (${t.network.config.name})`
1237
+ );
904
1238
  return createError(
905
1239
  "FACILITATOR_NO_TOKEN_SUPPORT",
906
1240
  `Facilitator "${facilitator.url}" does not support token "${token.config.symbol}" on "${token.network.config.name}". Supported: ${supportedTokens.join(", ")}`,
907
1241
  {
908
- value: { facilitator: facilitator.url, token: token.config.symbol, network: token.network.config.name },
1242
+ value: {
1243
+ facilitator: facilitator.url,
1244
+ token: token.config.symbol,
1245
+ network: token.network.config.name
1246
+ },
909
1247
  validOptions: supportedTokens
910
1248
  }
911
1249
  );
@@ -926,11 +1264,19 @@ var validatePaymentConfig = (network, token, facilitators, payTo = "0x0000000000
926
1264
  if (facilitators) {
927
1265
  const facilitatorArray = Array.isArray(facilitators) ? facilitators : [facilitators];
928
1266
  for (const facilitator of facilitatorArray) {
929
- const resolved = resolveFacilitator(facilitator, [resolvedNetwork], [resolvedToken]);
1267
+ const resolved = resolveFacilitator(
1268
+ facilitator,
1269
+ [resolvedNetwork],
1270
+ [resolvedToken]
1271
+ );
930
1272
  if ("code" in resolved) {
931
1273
  return resolved;
932
1274
  }
933
- const supportCheck = checkFacilitatorSupport(resolved, resolvedNetwork, resolvedToken);
1275
+ const supportCheck = checkFacilitatorSupport(
1276
+ resolved,
1277
+ resolvedNetwork,
1278
+ resolvedToken
1279
+ );
934
1280
  if ("code" in supportCheck) {
935
1281
  return supportCheck;
936
1282
  }
@@ -947,7 +1293,12 @@ var validatePaymentConfig = (network, token, facilitators, payTo = "0x0000000000
947
1293
  };
948
1294
  };
949
1295
  var validateAcceptConfig = (options, payTo, amount) => {
950
- const { networks: networkInputs, tokens: tokenInputs, facilitators, version = 2 } = options;
1296
+ const {
1297
+ networks: networkInputs,
1298
+ tokens: tokenInputs,
1299
+ facilitators,
1300
+ version = 2
1301
+ } = options;
951
1302
  const networkIds = networkInputs?.length ? networkInputs : Object.keys(NETWORKS);
952
1303
  const tokenIds = tokenInputs?.length ? tokenInputs : ["usdc"];
953
1304
  const networks = [];
@@ -960,17 +1311,16 @@ var validateAcceptConfig = (options, payTo, amount) => {
960
1311
  }
961
1312
  const tokens = [];
962
1313
  for (const tokenId of tokenIds) {
963
- let found = false;
1314
+ let matches = 0;
964
1315
  for (const network of networks) {
965
1316
  const resolved = resolveToken(tokenId, network);
966
1317
  if ("code" in resolved) {
967
1318
  continue;
968
1319
  }
969
1320
  tokens.push(resolved);
970
- found = true;
971
- break;
1321
+ matches += 1;
972
1322
  }
973
- if (!found) {
1323
+ if (matches === 0) {
974
1324
  return {
975
1325
  success: false,
976
1326
  error: createError(
@@ -1017,6 +1367,343 @@ var isResolvedToken = (value) => {
1017
1367
  return typeof value === "object" && value !== null && "config" in value && "caipAsset" in value;
1018
1368
  };
1019
1369
 
1370
+ // src/payment-requirements.ts
1371
+ var DEFAULT_NETWORKS = [
1372
+ "ethereum",
1373
+ "base",
1374
+ "base-sepolia",
1375
+ "skale-base",
1376
+ "skale-base-sepolia",
1377
+ "ethereum-sepolia"
1378
+ ];
1379
+ var DEFAULT_TOKENS = ["usdc"];
1380
+ var isValidationError2 = (value) => {
1381
+ return typeof value === "object" && value !== null && "code" in value;
1382
+ };
1383
+ function resolvePayTo(config, network, token) {
1384
+ const chainId = network.config.chainId;
1385
+ if (config.payToByToken) {
1386
+ for (const [chainKey, tokenMap] of Object.entries(config.payToByToken)) {
1387
+ const resolvedChain = resolveNetwork(chainKey);
1388
+ if (!isValidationError2(resolvedChain) && resolvedChain.config.chainId === chainId) {
1389
+ for (const [tokenKey2, address] of Object.entries(tokenMap)) {
1390
+ const resolvedToken = resolveToken(tokenKey2, network);
1391
+ if (!isValidationError2(resolvedToken) && resolvedToken.config.contractAddress.toLowerCase() === token.config.contractAddress.toLowerCase()) {
1392
+ return address;
1393
+ }
1394
+ }
1395
+ }
1396
+ }
1397
+ }
1398
+ if (config.payToByChain) {
1399
+ for (const [chainKey, address] of Object.entries(config.payToByChain)) {
1400
+ const resolvedChain = resolveNetwork(chainKey);
1401
+ if (!isValidationError2(resolvedChain) && resolvedChain.config.chainId === chainId) {
1402
+ return address;
1403
+ }
1404
+ }
1405
+ }
1406
+ return config.payTo;
1407
+ }
1408
+ function resolveFacilitatorUrl(config, network, token) {
1409
+ const chainId = network.config.chainId;
1410
+ if (config.facilitatorUrlByToken) {
1411
+ for (const [chainKey, tokenMap] of Object.entries(
1412
+ config.facilitatorUrlByToken
1413
+ )) {
1414
+ const resolvedChain = resolveNetwork(chainKey);
1415
+ if (!isValidationError2(resolvedChain) && resolvedChain.config.chainId === chainId) {
1416
+ for (const [tokenKey2, url] of Object.entries(tokenMap)) {
1417
+ const resolvedToken = resolveToken(tokenKey2, network);
1418
+ if (!isValidationError2(resolvedToken) && resolvedToken.config.contractAddress.toLowerCase() === token.config.contractAddress.toLowerCase()) {
1419
+ return url;
1420
+ }
1421
+ }
1422
+ }
1423
+ }
1424
+ }
1425
+ if (config.facilitatorUrlByChain) {
1426
+ for (const [chainKey, url] of Object.entries(
1427
+ config.facilitatorUrlByChain
1428
+ )) {
1429
+ const resolvedChain = resolveNetwork(chainKey);
1430
+ if (!isValidationError2(resolvedChain) && resolvedChain.config.chainId === chainId) {
1431
+ return url;
1432
+ }
1433
+ }
1434
+ }
1435
+ return config.facilitatorUrl;
1436
+ }
1437
+ function resolveFacilitatorUrlFromRequirement(config, requirement) {
1438
+ const chainId = parseInt(requirement.network.split(":")[1] || "0", 10);
1439
+ const assetAddress = requirement.asset.toLowerCase();
1440
+ if (config.facilitatorUrlByToken) {
1441
+ for (const [chainKey, tokenMap] of Object.entries(
1442
+ config.facilitatorUrlByToken
1443
+ )) {
1444
+ const resolvedChain = resolveNetwork(chainKey);
1445
+ if (isValidationError2(resolvedChain) || resolvedChain.config.chainId !== chainId) {
1446
+ continue;
1447
+ }
1448
+ for (const [tokenKey2, url] of Object.entries(tokenMap)) {
1449
+ const resolvedToken = resolveToken(tokenKey2, resolvedChain);
1450
+ if (!isValidationError2(resolvedToken) && resolvedToken.config.contractAddress.toLowerCase() === assetAddress) {
1451
+ return url;
1452
+ }
1453
+ }
1454
+ }
1455
+ }
1456
+ if (config.facilitatorUrlByChain) {
1457
+ for (const [chainKey, url] of Object.entries(
1458
+ config.facilitatorUrlByChain
1459
+ )) {
1460
+ const resolvedChain = resolveNetwork(chainKey);
1461
+ if (!isValidationError2(resolvedChain) && resolvedChain.config.chainId === chainId) {
1462
+ return url;
1463
+ }
1464
+ }
1465
+ }
1466
+ return config.facilitatorUrl;
1467
+ }
1468
+ function resolveNetworks(chainInputs) {
1469
+ const resolvedNetworks = [];
1470
+ const errors = [];
1471
+ const networks = chainInputs?.length ? chainInputs : DEFAULT_NETWORKS;
1472
+ for (const networkId of networks) {
1473
+ const resolved = resolveNetwork(networkId);
1474
+ if (isValidationError2(resolved)) {
1475
+ errors.push(`Network "${networkId}": ${resolved.message}`);
1476
+ } else {
1477
+ resolvedNetworks.push(resolved);
1478
+ }
1479
+ }
1480
+ if (errors.length > 0) {
1481
+ return {
1482
+ networks: resolvedNetworks,
1483
+ error: {
1484
+ code: "VALIDATION_FAILED",
1485
+ message: errors.join("; ")
1486
+ }
1487
+ };
1488
+ }
1489
+ return { networks: resolvedNetworks };
1490
+ }
1491
+ function createPaymentRequirements(config) {
1492
+ const {
1493
+ payTo,
1494
+ chains,
1495
+ chain,
1496
+ tokens,
1497
+ token,
1498
+ amount = "1.0",
1499
+ maxTimeoutSeconds = 300
1500
+ } = config;
1501
+ const chainInputs = chain ? [chain] : chains;
1502
+ const tokenInputs = token ? [token] : tokens;
1503
+ const { networks, error: networksError } = resolveNetworks(chainInputs);
1504
+ if (networksError) {
1505
+ return { requirements: [], error: networksError };
1506
+ }
1507
+ const requirements = [];
1508
+ for (const network of networks) {
1509
+ const tokensToResolve = tokenInputs?.length ? tokenInputs : DEFAULT_TOKENS;
1510
+ for (const tokenId of tokensToResolve) {
1511
+ const resolvedToken = resolveToken(tokenId, network);
1512
+ if (isValidationError2(resolvedToken)) {
1513
+ continue;
1514
+ }
1515
+ const atomicAmount = toAtomicUnits(amount);
1516
+ const tokenConfig = resolvedToken.config;
1517
+ const resolvedPayTo = resolvePayTo(config, network, resolvedToken);
1518
+ resolveFacilitatorUrl(
1519
+ config,
1520
+ network,
1521
+ resolvedToken
1522
+ );
1523
+ const requirement = {
1524
+ scheme: "exact",
1525
+ network: network.caip2,
1526
+ amount: atomicAmount,
1527
+ asset: tokenConfig.contractAddress,
1528
+ payTo: resolvedPayTo,
1529
+ maxTimeoutSeconds,
1530
+ extra: {
1531
+ name: tokenConfig.name,
1532
+ version: tokenConfig.version
1533
+ }
1534
+ };
1535
+ requirements.push(requirement);
1536
+ }
1537
+ }
1538
+ if (requirements.length === 0) {
1539
+ return {
1540
+ requirements: [],
1541
+ error: {
1542
+ code: "VALIDATION_FAILED",
1543
+ message: "No valid network/token combinations found"
1544
+ }
1545
+ };
1546
+ }
1547
+ return { requirements };
1548
+ }
1549
+ function findRequirementByNetwork(requirements, network) {
1550
+ const normalized = normalizeNetworkName(network);
1551
+ const netConfig = getNetworkConfig(normalized);
1552
+ if (!netConfig) return void 0;
1553
+ return requirements.find((r) => r.network === netConfig.caip2Id);
1554
+ }
1555
+ function findRequirementByAccepted(requirements, accepted) {
1556
+ const acceptedPayTo = typeof accepted.payTo === "string" ? accepted.payTo.toLowerCase() : "";
1557
+ const exactMatch = requirements.find(
1558
+ (requirement) => requirement.scheme === accepted.scheme && requirement.network === accepted.network && requirement.amount === accepted.amount && requirement.asset.toLowerCase() === accepted.asset.toLowerCase() && typeof requirement.payTo === "string" && requirement.payTo.toLowerCase() === acceptedPayTo
1559
+ );
1560
+ if (exactMatch) {
1561
+ return exactMatch;
1562
+ }
1563
+ const payToAwareMatch = requirements.find(
1564
+ (requirement) => requirement.scheme === accepted.scheme && requirement.network === accepted.network && acceptedPayTo.length > 0 && typeof requirement.payTo === "string" && requirement.payTo.toLowerCase() === acceptedPayTo
1565
+ );
1566
+ if (payToAwareMatch) {
1567
+ return payToAwareMatch;
1568
+ }
1569
+ return requirements.find(
1570
+ (requirement) => requirement.scheme === accepted.scheme && requirement.network === accepted.network
1571
+ );
1572
+ }
1573
+
1574
+ // src/facilitator-capabilities.ts
1575
+ var DEFAULT_CAPABILITY_TTL_MS = 5 * 60 * 1e3;
1576
+ var capabilityCache = /* @__PURE__ */ new Map();
1577
+ var normalizeNetwork = (network) => {
1578
+ return network.toLowerCase();
1579
+ };
1580
+ async function getExtensionKeysForFacilitator(url, network, ttlMs) {
1581
+ const cacheKey = `${url}|${normalizeNetwork(network)}`;
1582
+ const now = Date.now();
1583
+ const cached = capabilityCache.get(cacheKey);
1584
+ if (cached && cached.expiresAt > now) {
1585
+ return cached.keys;
1586
+ }
1587
+ try {
1588
+ const supported = await getSupported({ url });
1589
+ const extensionKeys = /* @__PURE__ */ new Set();
1590
+ for (const kind of supported.kinds) {
1591
+ if (normalizeNetwork(kind.network) !== normalizeNetwork(network)) {
1592
+ continue;
1593
+ }
1594
+ if (kind.extra && typeof kind.extra === "object") {
1595
+ for (const key of Object.keys(kind.extra)) {
1596
+ extensionKeys.add(key);
1597
+ }
1598
+ }
1599
+ }
1600
+ capabilityCache.set(cacheKey, {
1601
+ expiresAt: now + ttlMs,
1602
+ keys: extensionKeys
1603
+ });
1604
+ return extensionKeys;
1605
+ } catch {
1606
+ capabilityCache.set(cacheKey, {
1607
+ expiresAt: now + ttlMs,
1608
+ keys: /* @__PURE__ */ new Set()
1609
+ });
1610
+ return /* @__PURE__ */ new Set();
1611
+ }
1612
+ }
1613
+ async function filterExtensionsForFacilitator(extensions, facilitatorUrl, network, ttlMs = DEFAULT_CAPABILITY_TTL_MS) {
1614
+ if (!extensions || !facilitatorUrl) {
1615
+ return extensions ?? {};
1616
+ }
1617
+ const supportedKeys = await getExtensionKeysForFacilitator(
1618
+ facilitatorUrl,
1619
+ network,
1620
+ ttlMs
1621
+ );
1622
+ const filtered = {};
1623
+ for (const [key, value] of Object.entries(extensions)) {
1624
+ if (supportedKeys.has(key)) {
1625
+ filtered[key] = value;
1626
+ }
1627
+ }
1628
+ return filtered;
1629
+ }
1630
+ async function filterExtensionsForFacilitators(extensions, facilitators, ttlMs = DEFAULT_CAPABILITY_TTL_MS) {
1631
+ if (!extensions) {
1632
+ return {};
1633
+ }
1634
+ let filtered = { ...extensions };
1635
+ for (const facilitator of facilitators) {
1636
+ filtered = await filterExtensionsForFacilitator(
1637
+ filtered,
1638
+ facilitator.url,
1639
+ facilitator.network,
1640
+ ttlMs
1641
+ );
1642
+ if (Object.keys(filtered).length === 0) {
1643
+ return {};
1644
+ }
1645
+ }
1646
+ return filtered;
1647
+ }
1648
+ async function filterExtensionsForRequirements(extensions, requirements, config, ttlMs = DEFAULT_CAPABILITY_TTL_MS) {
1649
+ const facilitators = requirements.map((requirement) => ({
1650
+ url: resolveFacilitatorUrlFromRequirement(config, requirement),
1651
+ network: requirement.network
1652
+ }));
1653
+ return filterExtensionsForFacilitators(extensions, facilitators, ttlMs);
1654
+ }
1655
+ function clearFacilitatorCapabilityCache() {
1656
+ capabilityCache.clear();
1657
+ }
1658
+
1659
+ // src/protocol.ts
1660
+ function parseJsonOrBase64(value) {
1661
+ try {
1662
+ return JSON.parse(value);
1663
+ } catch {
1664
+ const normalized = normalizeBase64Url(value);
1665
+ return JSON.parse(decodeBase64ToUtf8(normalized));
1666
+ }
1667
+ }
1668
+ function detectX402Version(_response) {
1669
+ return 2;
1670
+ }
1671
+ function getPaymentHeaderName(_version) {
1672
+ return V2_HEADERS.PAYMENT_SIGNATURE;
1673
+ }
1674
+ function generateNonce() {
1675
+ const now = Math.floor(Date.now() / 1e3);
1676
+ return `0x${(now * 1e3).toString(16).padStart(64, "0")}`;
1677
+ }
1678
+ function calculateValidBefore(expirySeconds = 3600) {
1679
+ return Math.floor(Date.now() / 1e3) + expirySeconds;
1680
+ }
1681
+
1682
+ // src/types/protocol.ts
1683
+ function isX402V2Payload(obj) {
1684
+ return typeof obj === "object" && obj !== null && "x402Version" in obj && obj.x402Version === 2 && "accepted" in obj && "payload" in obj;
1685
+ }
1686
+ function isX402V2Requirements(obj) {
1687
+ return typeof obj === "object" && obj !== null && "scheme" in obj && obj.scheme === "exact" && "network" in obj && typeof obj.network === "string" && obj.network.startsWith("eip155:") && // CAIP-2 format
1688
+ "amount" in obj && "asset" in obj && "payTo" in obj && "maxTimeoutSeconds" in obj;
1689
+ }
1690
+ function isX402V2Settlement(obj) {
1691
+ return typeof obj === "object" && obj !== null && "success" in obj && typeof obj.success === "boolean" && "network" in obj && typeof obj.network === "string" && obj.network.startsWith("eip155:");
1692
+ }
1693
+ function isX402V2PaymentRequired(obj) {
1694
+ return typeof obj === "object" && obj !== null && "x402Version" in obj && obj.x402Version === 2 && "resource" in obj && "accepts" in obj;
1695
+ }
1696
+ var PAYMENT_SIGNATURE_HEADER = "PAYMENT-SIGNATURE";
1697
+ var PAYMENT_RESPONSE_HEADER = "PAYMENT-RESPONSE";
1698
+ var PAYMENT_REQUIRED_HEADER = "PAYMENT-REQUIRED";
1699
+ function isSettlementSuccessful(response) {
1700
+ return "success" in response ? response.success : false;
1701
+ }
1702
+ function getTxHash(response) {
1703
+ if ("transaction" in response) return response.transaction;
1704
+ return void 0;
1705
+ }
1706
+
1020
1707
  // src/utils/routes.ts
1021
1708
  var PRIORITY_EXACT = 3;
1022
1709
  var PRIORITY_PARAMETRIZED = 2;
@@ -1083,7 +1770,7 @@ function matchSegment(patternSegment, pathSegment) {
1083
1770
  }
1084
1771
  if (patternSegment.includes("*")) {
1085
1772
  const regex = new RegExp(
1086
- "^" + patternSegment.replace(/\*/g, ".*").replace(/:/g, "") + "$"
1773
+ `^${patternSegment.replace(/\*/g, ".*").replace(/:/g, "")}$`
1087
1774
  );
1088
1775
  return regex.test(pathSegment);
1089
1776
  }
@@ -1096,7 +1783,7 @@ function matchWildcardPattern(patternSegments, pathSegments) {
1096
1783
  }
1097
1784
  for (let i = 0; i < requiredSegments.length; i++) {
1098
1785
  const patternIndex = patternSegments.indexOf(requiredSegments[i]);
1099
- if (pathSegments[patternIndex] !== requiredSegments[i].replace(/^\:/, "")) {
1786
+ if (pathSegments[patternIndex] !== requiredSegments[i].replace(/^:/, "")) {
1100
1787
  if (!requiredSegments[i].startsWith(":") && requiredSegments[i] !== "*") {
1101
1788
  return false;
1102
1789
  }
@@ -1173,152 +1860,13 @@ function validateRouteConfig(config) {
1173
1860
  message: `Wildcard routes must use the routes array, not 'route'. Use 'routes: ["/api/*"]' instead of 'route: "/api/*"'.`,
1174
1861
  path: "route",
1175
1862
  value: route,
1176
- validOptions: ['routes: ["/api/*"]', 'routes: ["/api/users", "/api/posts"]']
1863
+ validOptions: [
1864
+ 'routes: ["/api/*"]',
1865
+ 'routes: ["/api/users", "/api/posts"]'
1866
+ ]
1177
1867
  };
1178
1868
  }
1179
1869
  return null;
1180
1870
  }
1181
1871
 
1182
- // src/encoding.ts
1183
- function safeBase64Decode2(str) {
1184
- const padding = 4 - str.length % 4;
1185
- if (padding !== 4) {
1186
- str += "=".repeat(padding);
1187
- }
1188
- str = str.replace(/-/g, "+").replace(/_/g, "/");
1189
- return Buffer.from(str, "base64").toString("utf-8");
1190
- }
1191
- function safeBase64Encode2(str) {
1192
- return Buffer.from(str).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
1193
- }
1194
- var base64JsonEncode = (data) => safeBase64Encode2(JSON.stringify(data));
1195
- var base64JsonDecode = (encoded) => JSON.parse(safeBase64Decode2(encoded));
1196
- var encodePaymentV2 = (payload) => base64JsonEncode(payload);
1197
- var decodePaymentV2 = (encoded) => base64JsonDecode(encoded);
1198
- var encodeSettlementV2 = (response) => base64JsonEncode(response);
1199
- var decodeSettlementV2 = (encoded) => base64JsonDecode(encoded);
1200
- var isPaymentV2 = (payload) => "x402Version" in payload && payload.x402Version === 2 && "accepted" in payload && "payload" in payload;
1201
- var isSettlementV2 = (response) => "success" in response && typeof response.success === "boolean" && "network" in response;
1202
-
1203
- // src/payment-client.ts
1204
- var DEFAULT_FACILITATOR_URL = "https://facilitator.payai.network";
1205
- function toJsonSafe(data) {
1206
- function convert(value) {
1207
- if (value !== null && typeof value === "object" && !Array.isArray(value)) {
1208
- return Object.fromEntries(Object.entries(value).map(([key, val]) => [key, convert(val)]));
1209
- }
1210
- if (Array.isArray(value)) {
1211
- return value.map(convert);
1212
- }
1213
- if (typeof value === "bigint") {
1214
- return value.toString();
1215
- }
1216
- return value;
1217
- }
1218
- return convert(data);
1219
- }
1220
- function resolveUrl(config) {
1221
- return config?.url ?? DEFAULT_FACILITATOR_URL;
1222
- }
1223
- async function resolveHeaders(config) {
1224
- const base = { "Content-Type": "application/json" };
1225
- if (!config?.createHeaders) return base;
1226
- const extra = await config.createHeaders();
1227
- return { ...base, ...extra };
1228
- }
1229
- async function verifyPayment(payload, requirements, config) {
1230
- const url = resolveUrl(config);
1231
- const headers = await resolveHeaders(config);
1232
- const response = await fetch(`${url}/verify`, {
1233
- method: "POST",
1234
- headers,
1235
- body: JSON.stringify({
1236
- paymentPayload: toJsonSafe(payload),
1237
- paymentRequirements: toJsonSafe(requirements)
1238
- })
1239
- });
1240
- if (response.status !== 200) {
1241
- const text = await response.text().catch(() => response.statusText);
1242
- throw new Error(`Facilitator verify failed: ${response.status} ${text}`);
1243
- }
1244
- return await response.json();
1245
- }
1246
- async function settlePayment(payload, requirements, config) {
1247
- const url = resolveUrl(config);
1248
- const headers = await resolveHeaders(config);
1249
- const response = await fetch(`${url}/settle`, {
1250
- method: "POST",
1251
- headers,
1252
- body: JSON.stringify({
1253
- paymentPayload: toJsonSafe(payload),
1254
- paymentRequirements: toJsonSafe(requirements)
1255
- })
1256
- });
1257
- if (response.status !== 200) {
1258
- const text = await response.text().catch(() => response.statusText);
1259
- throw new Error(`Facilitator settle failed: ${response.status} ${text}`);
1260
- }
1261
- return await response.json();
1262
- }
1263
- async function getSupported(config) {
1264
- const url = resolveUrl(config);
1265
- const headers = await resolveHeaders(config);
1266
- const response = await fetch(`${url}/supported`, {
1267
- method: "GET",
1268
- headers
1269
- });
1270
- if (response.status !== 200) {
1271
- throw new Error(`Facilitator supported failed: ${response.statusText}`);
1272
- }
1273
- return await response.json();
1274
- }
1275
- function isCompactV2Payload(payload) {
1276
- if (typeof payload !== "object" || payload === null) return false;
1277
- const record = payload;
1278
- return typeof record.x402Version === "number" && "payload" in record && !("accepted" in record);
1279
- }
1280
- function decodePayloadHeader(headerValue, defaults) {
1281
- if (headerValue.startsWith("{")) {
1282
- const parsed = JSON.parse(headerValue);
1283
- if (isPaymentPayload(parsed)) return parsed;
1284
- if (isCompactV2Payload(parsed)) {
1285
- const compact = parsed;
1286
- if (!defaults?.accepted) {
1287
- throw new Error("Invalid payment payload: missing 'accepted' field and no defaults provided");
1288
- }
1289
- return {
1290
- x402Version: 2,
1291
- accepted: defaults.accepted,
1292
- payload: compact.payload
1293
- };
1294
- }
1295
- throw new Error("Invalid payment payload: unrecognized format");
1296
- }
1297
- const normalized = headerValue.replace(/-/g, "+").replace(/_/g, "/").padEnd(Math.ceil(headerValue.length / 4) * 4, "=");
1298
- try {
1299
- const decoded = JSON.parse(Buffer.from(normalized, "base64").toString("utf-8"));
1300
- if (isPaymentPayload(decoded)) return decoded;
1301
- if (isCompactV2Payload(decoded)) {
1302
- const compact = decoded;
1303
- if (!defaults?.accepted) {
1304
- throw new Error("Invalid payment payload: missing 'accepted' field and no defaults provided");
1305
- }
1306
- return {
1307
- x402Version: 2,
1308
- accepted: defaults.accepted,
1309
- payload: compact.payload
1310
- };
1311
- }
1312
- throw new Error("Invalid payment payload: unrecognized format");
1313
- } catch {
1314
- throw new Error("Invalid payment payload: failed to decode");
1315
- }
1316
- }
1317
- function extractPayerAddress(payload) {
1318
- if (isExactEvmPayload(payload.payload)) {
1319
- return payload.payload.authorization.from;
1320
- }
1321
- throw new Error("Unable to extract payer address from payload");
1322
- }
1323
-
1324
- export { EIP712_TYPES, ERC20_ABI, EURC_BASE, NETWORKS, PAYMENT_REQUIRED_HEADER, PAYMENT_RESPONSE_HEADER, PAYMENT_SIGNATURE_HEADER, SCHEMES, SKL_SKALE_BASE, SKL_SKALE_BASE_SEPOLIA, TOKENS, USDC_BASE, USDC_BASE_SEPOLIA, USDC_DOMAIN, USDC_SKALE_BASE, USDC_SKALE_BASE_SEPOLIA, USDT_SKALE_BASE, USDT_SKALE_BASE_SEPOLIA, V2_HEADERS, WBTC_SKALE_BASE, WBTC_SKALE_BASE_SEPOLIA, WETH_SKALE_BASE, WETH_SKALE_BASE_SEPOLIA, X402_VERSION, addressToAssetId, assetIdToAddress, caip2ToNetwork, checkFacilitatorSupport, combineSignature as combineSignatureV2, createEIP712Domain, createError, createNonce, createPaymentRequiredHeaders, createSettlementHeaders, createTransferWithAuthorization, decodePayloadHeader, decodePayment, decodePaymentV2, decodeSettlementResponse, decodeSettlementV2, decodeX402Response, detectPaymentVersion, encodePayment, encodePaymentV2, encodeSettlementResponse, encodeSettlementV2, encodeX402Response, extractPayerAddress, extractPaymentFromHeaders, findMatchingRoute, fromAtomicUnits, getAllCustomTokens, getAllTokens, getAvailableNetworks, getAvailableTokens, getCurrentTimestamp, getCustomToken, getEURCTokens, getMainnets, getNetworkByChainId, getNetworkConfig, getSKLTokens, getSupported, getTestnets, getToken, getTokensByChain, getTokensBySymbol, getTxHash, getUSDCTokens, getUSDTTokens, getWBTCTokens, getWETHTokens, isAddress, isCAIP2ChainId, isCAIPAssetId, isCustomToken, isExactEvmPayload, isPaymentPayload, isPaymentPayloadV2, isPaymentRequiredV2, isPaymentV2, isResolvedNetwork, isResolvedToken, isSettlementSuccessful, isSettlementV2, isValidAddress, isValidationError, isX402V2Payload, isX402V2PaymentRequired, isX402V2Requirements, isX402V2Settlement, matchRoute, networkToCaip2, normalizeAddress, normalizeNetworkName, parseRoutePattern, parseSignature as parseSignatureV2, registerToken, resolveFacilitator, resolveNetwork, resolveToken, safeBase64Decode, safeBase64Encode, settlePayment, toAtomicUnits, unregisterToken, validateAcceptConfig, validatePaymentConfig, validateRouteConfig, validateTransferWithAuthorization, verifyPayment };
1872
+ export { EIP712_TYPES, ERC20_ABI, EURC_BASE, NETWORKS, PAYMENT_REQUIRED_HEADER, PAYMENT_RESPONSE_HEADER, PAYMENT_SIGNATURE_HEADER, PaymentException, SCHEMES, SKL_SKALE_BASE, SKL_SKALE_BASE_SEPOLIA, SigningError, TOKENS, USDC_BASE, USDC_BASE_SEPOLIA, USDC_DOMAIN, USDC_SKALE_BASE, USDC_SKALE_BASE_SEPOLIA, USDT_SKALE_BASE, USDT_SKALE_BASE_SEPOLIA, V2_HEADERS, WBTC_SKALE_BASE, WBTC_SKALE_BASE_SEPOLIA, WETH_SKALE_BASE, WETH_SKALE_BASE_SEPOLIA, X402ClientError, X402_VERSION, addressToAssetId, assetIdToAddress, caip2ToNetwork, calculateValidBefore, checkFacilitatorSupport, clearFacilitatorCapabilityCache, combineSignature as combineSignatureV2, createEIP712Domain, createError, createNonce, createPaymentRequiredHeaders, createPaymentRequirements, createSettlementHeaders, createTransferWithAuthorization, decodeBase64ToUtf8, decodePayloadHeader, decodePayment, decodePaymentV2, decodeSettlementResponse, decodeSettlementV2, decodeX402Response, detectPaymentVersion, detectX402Version, encodePayment, encodePaymentV2, encodeSettlementResponse, encodeSettlementV2, encodeUtf8ToBase64, encodeX402Response, extractPayerAddress, extractPaymentFromHeaders, filterExtensionsForFacilitator, filterExtensionsForFacilitators, filterExtensionsForRequirements, findMatchingRoute, findRequirementByAccepted, findRequirementByNetwork, fromAtomicUnits, generateNonce, getAllCustomTokens, getAllTokens, getAvailableNetworks, getAvailableTokens, getCurrentTimestamp, getCustomToken, getEURCTokens, getMainnets, getNetworkByChainId, getNetworkConfig, getPaymentHeaderName, getSKLTokens, getSupported, getTestnets, getToken, getTokensByChain, getTokensBySymbol, getTxHash, getUSDCTokens, getUSDTTokens, getWBTCTokens, getWETHTokens, isAddress2 as isAddress, isCAIP2ChainId, isCAIPAssetId, isCustomToken, isExactEvmPayload, isPaymentPayload, isPaymentPayloadV2, isPaymentRequiredV2, isPaymentV2, isResolvedNetwork, isResolvedToken, isSettlementSuccessful, isSettlementV2, isValidAddress, isValidationError, isX402V2Payload, isX402V2PaymentRequired, isX402V2Requirements, isX402V2Settlement, matchRoute, networkToCaip2, normalizeAddress, normalizeBase64Url, normalizeNetworkName, parseJsonOrBase64, parseRoutePattern, parseSignature as parseSignatureV2, registerToken, resolveFacilitator, resolveFacilitatorUrlFromRequirement, resolveNetwork, resolveToken, runAfterPaymentResponseHooks, runBeforeSignPaymentHooks, runOnPaymentRequiredHooks, safeBase64Decode2 as safeBase64Decode, safeBase64Encode2 as safeBase64Encode, selectRequirementWithHooks, settlePayment, toAtomicUnits, toBase64Url, unregisterToken, validateAcceptConfig, validatePaymentConfig, validateRouteConfig, validateTransferWithAuthorization, verifyPayment };