@armory-sh/base 0.2.27-alpha.23.76 → 0.2.27-alpha.23.78

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.js CHANGED
@@ -1,385 +1,161 @@
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;
8
- }
9
- function isExactEvmPayload(obj) {
10
- return typeof obj === "object" && obj !== null && "signature" in obj && "authorization" in obj;
11
- }
12
-
13
- // src/types/v2.ts
14
- var V2_HEADERS = {
15
- PAYMENT_SIGNATURE: "PAYMENT-SIGNATURE",
16
- PAYMENT_REQUIRED: "PAYMENT-REQUIRED",
17
- PAYMENT_RESPONSE: "PAYMENT-RESPONSE"
18
- };
19
- function isCAIP2ChainId(value) {
20
- return /^eip155:\d+$/.test(value);
21
- }
22
- function isCAIPAssetId(value) {
23
- return /^eip155:\d+\/erc20:0x[a-fA-F0-9]+$/.test(value);
24
- }
25
- function isAddress(value) {
26
- return /^0x[a-fA-F0-9]{40}$/.test(value);
27
- }
28
- function isPaymentRequiredV2(obj) {
29
- return typeof obj === "object" && obj !== null && "x402Version" in obj && obj.x402Version === 2 && "resource" in obj && "accepts" in obj && Array.isArray(obj.accepts);
30
- }
31
- function isPaymentPayloadV2(obj) {
32
- return typeof obj === "object" && obj !== null && "x402Version" in obj && obj.x402Version === 2 && "accepted" in obj && "payload" in obj;
33
- }
34
- function assetIdToAddress(assetId) {
35
- const match = assetId.match(/\/erc20:(0x[a-fA-F0-9]{40})$/);
36
- if (!match) throw new Error(`Invalid CAIP asset ID: ${assetId}`);
37
- return match[1];
38
- }
39
- function addressToAssetId(address, chainId) {
40
- const chain = typeof chainId === "number" ? `eip155:${chainId}` : chainId;
41
- if (!isCAIP2ChainId(chain)) throw new Error(`Invalid chain ID: ${chain}`);
42
- return `${chain}/erc20:${address}`;
43
- }
44
- function parseSignature(signature) {
45
- const sig = signature.slice(2);
46
- return {
47
- r: `0x${sig.slice(0, 64)}`,
48
- s: `0x${sig.slice(64, 128)}`,
49
- v: parseInt(sig.slice(128, 130), 16)
50
- };
51
- }
52
- function combineSignature(v, r, s) {
53
- const rClean = r.startsWith("0x") ? r.slice(2) : r;
54
- const sClean = s.startsWith("0x") ? s.slice(2) : s;
55
- const vHex = v.toString(16).padStart(2, "0");
56
- return `0x${rClean}${sClean}${vHex}`;
57
- }
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
+ ];
58
59
 
59
- // src/utils/base64.ts
60
- var textEncoder = new TextEncoder();
61
- var textDecoder = new TextDecoder();
62
- function toBase64(bytes) {
63
- if (typeof btoa === "function") {
64
- let binary = "";
65
- for (let index = 0; index < bytes.length; index += 1) {
66
- binary += String.fromCharCode(bytes[index]);
67
- }
68
- return btoa(binary);
60
+ // src/client-hooks-runtime.ts
61
+ var notifyError = async (hooks, context) => {
62
+ if (!hooks?.length) {
63
+ return;
69
64
  }
70
- throw new Error("No base64 encoder available in this runtime");
71
- }
72
- function fromBase64(base64) {
73
- if (typeof atob === "function") {
74
- const binary = atob(base64);
75
- const bytes = new Uint8Array(binary.length);
76
- for (let index = 0; index < binary.length; index += 1) {
77
- bytes[index] = binary.charCodeAt(index);
65
+ for (const hook of hooks) {
66
+ if (!hook.onError) {
67
+ continue;
78
68
  }
79
- return bytes;
69
+ await hook.onError(context);
80
70
  }
81
- throw new Error("No base64 decoder available in this runtime");
82
- }
83
- function encodeUtf8ToBase64(value) {
84
- const bytes = textEncoder.encode(value);
85
- return toBase64(bytes);
86
- }
87
- function decodeBase64ToUtf8(value) {
88
- const bytes = fromBase64(value);
89
- return textDecoder.decode(bytes);
90
- }
91
- function toBase64Url(base64) {
92
- return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
93
- }
94
- function normalizeBase64Url(value) {
95
- return value.replace(/-/g, "+").replace(/_/g, "/").padEnd(Math.ceil(value.length / 4) * 4, "=");
96
- }
97
-
98
- // src/encoding/x402.ts
99
- function safeBase64Encode(str) {
100
- return toBase64Url(encodeUtf8ToBase64(str));
101
- }
102
- function safeBase64Decode(str) {
103
- return decodeBase64ToUtf8(normalizeBase64Url(str));
104
- }
105
- function encodePayment(payload) {
106
- if (!isPaymentPayload(payload)) {
107
- throw new Error("Invalid payment payload format");
71
+ };
72
+ var runOnPaymentRequiredHooks = async (hooks, context) => {
73
+ if (!hooks?.length) {
74
+ return;
108
75
  }
109
- const safePayload = JSON.parse(JSON.stringify(payload, (_, value) => {
110
- if (typeof value === "bigint") {
111
- return value.toString();
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;
112
85
  }
113
- return value;
114
- }));
115
- return safeBase64Encode(JSON.stringify(safePayload));
116
- }
117
- function decodePayment(encoded) {
118
- let parsed;
119
- try {
120
- parsed = JSON.parse(encoded);
121
- } catch {
122
- const decoded = safeBase64Decode(encoded);
123
- parsed = JSON.parse(decoded);
124
- }
125
- if (!isPaymentPayload(parsed)) {
126
- throw new Error("Invalid payment payload format");
127
86
  }
128
- return parsed;
129
- }
130
- function encodeSettlementResponse(response) {
131
- const safeResponse = JSON.parse(JSON.stringify(response, (_, value) => {
132
- if (typeof value === "bigint") {
133
- return value.toString();
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;
134
121
  }
135
- return value;
136
- }));
137
- return safeBase64Encode(JSON.stringify(safeResponse));
138
- }
139
- function decodeSettlementResponse(encoded) {
140
- try {
141
- return JSON.parse(encoded);
142
- } catch {
143
- const decoded = safeBase64Decode(encoded);
144
- return JSON.parse(decoded);
145
122
  }
146
- }
147
- function encodeX402Response(response) {
148
- return safeBase64Encode(JSON.stringify(response));
149
- }
150
- function decodeX402Response(encoded) {
151
- try {
152
- return JSON.parse(encoded);
153
- } catch {
154
- const decoded = safeBase64Decode(encoded);
155
- return JSON.parse(decoded);
123
+ context.selectedRequirement = selected;
124
+ context.requirements = selected;
125
+ return selected;
126
+ };
127
+ var runBeforeSignPaymentHooks = async (hooks, context) => {
128
+ if (!hooks?.length) {
129
+ return;
156
130
  }
157
- }
158
- function detectPaymentVersion(headers) {
159
- if (headers.has("PAYMENT-SIGNATURE")) {
160
- return 2;
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
+ }
161
141
  }
162
- return null;
163
- }
164
- function extractPaymentFromHeaders(headers) {
165
- const encoded = headers.get("PAYMENT-SIGNATURE");
166
- if (!encoded) return null;
167
- try {
168
- return decodePayment(encoded);
169
- } catch {
170
- return null;
142
+ };
143
+ var runAfterPaymentResponseHooks = async (hooks, context) => {
144
+ if (!hooks?.length) {
145
+ return;
171
146
  }
172
- }
173
- function createPaymentRequiredHeaders(requirements, options) {
174
- const accepts = Array.isArray(requirements) ? requirements : [requirements];
175
- const response = {
176
- x402Version: 2,
177
- error: options?.error ?? "Payment required",
178
- resource: options?.resource ?? { url: "", mimeType: "application/json" },
179
- accepts,
180
- extensions: options?.extensions ?? {}
181
- };
182
- return {
183
- [V2_HEADERS.PAYMENT_REQUIRED]: safeBase64Encode(JSON.stringify(response))
184
- };
185
- }
186
- function createSettlementHeaders(settlement) {
187
- return {
188
- [V2_HEADERS.PAYMENT_RESPONSE]: encodeSettlementResponse(settlement)
189
- };
190
- }
191
- function createNonce() {
192
- const bytes = randomBytes(32);
193
- return `0x${bytes.toString("hex")}`;
194
- }
195
- function toAtomicUnits(amount, decimals = 6) {
196
- const parts = amount.split(".");
197
- const whole = parts[0];
198
- const fractional = parts[1] || "";
199
- const paddedFractional = fractional.padEnd(decimals, "0").slice(0, decimals);
200
- return `${whole}${paddedFractional}`;
201
- }
202
- function fromAtomicUnits(amount, decimals = 6) {
203
- const value = BigInt(amount);
204
- const divisor = BigInt(10 ** decimals);
205
- const whole = (value / divisor).toString();
206
- const fractional = (value % divisor).toString().padStart(decimals, "0").replace(/0+$/, "");
207
- if (fractional.length === 0) {
208
- return whole;
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
+ }
209
157
  }
210
- return `${whole}.${fractional}`;
211
- }
212
- function caip2ToNetwork(caip2Id) {
213
- const match = caip2Id.match(/^eip155:(\d+)$/);
214
- if (!match) {
215
- return caip2Id;
216
- }
217
- const chainId = parseInt(match[1], 10);
218
- const chainIdToNetwork = {
219
- 1: "ethereum",
220
- 8453: "base",
221
- 84532: "base-sepolia",
222
- 137: "polygon",
223
- 42161: "arbitrum",
224
- 421614: "arbitrum-sepolia",
225
- 10: "optimism",
226
- 11155420: "optimism-sepolia",
227
- 11155111: "ethereum-sepolia"
228
- };
229
- return chainIdToNetwork[chainId] || caip2Id;
230
- }
231
- function networkToCaip2(network) {
232
- const networkToChainId = {
233
- ethereum: 1,
234
- base: 8453,
235
- "base-sepolia": 84532,
236
- polygon: 137,
237
- arbitrum: 42161,
238
- "arbitrum-sepolia": 421614,
239
- optimism: 10,
240
- "optimism-sepolia": 11155420,
241
- "ethereum-sepolia": 11155111
242
- };
243
- const chainId = networkToChainId[network];
244
- if (chainId) {
245
- return `eip155:${chainId}`;
246
- }
247
- if (network.startsWith("eip155:")) {
248
- return network;
249
- }
250
- return `eip155:0`;
251
- }
252
- function getCurrentTimestamp() {
253
- return Math.floor(Date.now() / 1e3);
254
- }
255
- function isValidAddress(address) {
256
- return /^0x[a-fA-F0-9]{40}$/.test(address);
257
- }
258
- function normalizeAddress(address) {
259
- return address.toLowerCase();
260
- }
261
-
262
- // src/types/protocol.ts
263
- function isX402V2Payload(obj) {
264
- return typeof obj === "object" && obj !== null && "x402Version" in obj && obj.x402Version === 2 && "accepted" in obj && "payload" in obj;
265
- }
266
- function isX402V2Requirements(obj) {
267
- 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
268
- "amount" in obj && "asset" in obj && "payTo" in obj && "maxTimeoutSeconds" in obj;
269
- }
270
- function isX402V2Settlement(obj) {
271
- return typeof obj === "object" && obj !== null && "success" in obj && typeof obj.success === "boolean" && "network" in obj && typeof obj.network === "string" && obj.network.startsWith("eip155:");
272
- }
273
- function isX402V2PaymentRequired(obj) {
274
- return typeof obj === "object" && obj !== null && "x402Version" in obj && obj.x402Version === 2 && "resource" in obj && "accepts" in obj;
275
- }
276
- var PAYMENT_SIGNATURE_HEADER = "PAYMENT-SIGNATURE";
277
- var PAYMENT_RESPONSE_HEADER = "PAYMENT-RESPONSE";
278
- var PAYMENT_REQUIRED_HEADER = "PAYMENT-REQUIRED";
279
- function isSettlementSuccessful(response) {
280
- return "success" in response ? response.success : false;
281
- }
282
- function getTxHash(response) {
283
- if ("transaction" in response) return response.transaction;
284
- return void 0;
285
- }
286
-
287
- // src/types/networks.ts
288
- var isEvmAddress = (value) => /^0x[a-fA-F0-9]{40}$/.test(value);
289
- var tokenRegistry = /* @__PURE__ */ new Map();
290
- var tokenKey = (chainId, contractAddress) => `${chainId}:${contractAddress.toLowerCase()}`;
291
- var NETWORKS = {
292
- ethereum: {
293
- name: "Ethereum Mainnet",
294
- chainId: 1,
295
- usdcAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
296
- rpcUrl: "https://eth.llamarpc.com",
297
- caip2Id: "eip155:1",
298
- caipAssetId: "eip155:1/erc20:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
299
- },
300
- base: {
301
- name: "Base Mainnet",
302
- chainId: 8453,
303
- usdcAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
304
- rpcUrl: "https://mainnet.base.org",
305
- caip2Id: "eip155:8453",
306
- caipAssetId: "eip155:8453/erc20:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
307
- },
308
- "base-sepolia": {
309
- name: "Base Sepolia",
310
- chainId: 84532,
311
- usdcAddress: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
312
- rpcUrl: "https://sepolia.base.org",
313
- caip2Id: "eip155:84532",
314
- caipAssetId: "eip155:84532/erc20:0x036CbD53842c5426634e7929541eC2318f3dCF7e"
315
- },
316
- "skale-base": {
317
- name: "SKALE Base",
318
- chainId: 1187947933,
319
- usdcAddress: "0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20",
320
- rpcUrl: "https://skale-base.skalenodes.com/v1/base",
321
- caip2Id: "eip155:1187947933",
322
- caipAssetId: "eip155:1187947933/erc20:0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20"
323
- },
324
- "skale-base-sepolia": {
325
- name: "SKALE Base Sepolia",
326
- chainId: 324705682,
327
- usdcAddress: "0x2e08028E3C4c2356572E096d8EF835cD5C6030bD",
328
- rpcUrl: "https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha",
329
- caip2Id: "eip155:324705682",
330
- caipAssetId: "eip155:324705682/erc20:0x2e08028E3C4c2356572E096d8EF835cD5C6030bD"
331
- },
332
- "ethereum-sepolia": {
333
- name: "Ethereum Sepolia",
334
- chainId: 11155111,
335
- usdcAddress: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
336
- rpcUrl: "https://rpc.sepolia.org",
337
- caip2Id: "eip155:11155111",
338
- caipAssetId: "eip155:11155111/erc20:0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238"
339
- }
340
- };
341
- var getNetworkConfig = (name) => NETWORKS[name];
342
- var getNetworkByChainId = (chainId) => Object.values(NETWORKS).find((c) => c.chainId === chainId);
343
- var getMainnets = () => Object.values(NETWORKS).filter((c) => !c.name.toLowerCase().includes("sepolia"));
344
- var getTestnets = () => Object.values(NETWORKS).filter((c) => c.name.toLowerCase().includes("sepolia"));
345
- var registerToken = (token) => {
346
- if (typeof token !== "object" || token === null) {
347
- throw new Error("Invalid token: must be an object");
348
- }
349
- const t = token;
350
- if (typeof t.symbol !== "string") {
351
- throw new Error("Invalid token: symbol must be a string");
352
- }
353
- if (typeof t.name !== "string") {
354
- throw new Error("Invalid token: name must be a string");
355
- }
356
- if (typeof t.version !== "string") {
357
- throw new Error("Invalid token: version must be a string");
358
- }
359
- if (typeof t.contractAddress !== "string" || !isEvmAddress(t.contractAddress)) {
360
- throw new Error("Invalid token: contractAddress must be a valid EVM address");
361
- }
362
- if (typeof t.chainId !== "number" || !Number.isInteger(t.chainId) || t.chainId <= 0) {
363
- throw new Error("Invalid token: chainId must be a positive integer");
364
- }
365
- if (t.decimals !== void 0 && (typeof t.decimals !== "number" || !Number.isInteger(t.decimals) || t.decimals < 0)) {
366
- throw new Error("Invalid token: decimals must be a non-negative integer");
367
- }
368
- const validated = {
369
- symbol: t.symbol,
370
- name: t.name,
371
- version: t.version,
372
- contractAddress: t.contractAddress,
373
- chainId: t.chainId,
374
- decimals: t.decimals
375
- };
376
- tokenRegistry.set(tokenKey(validated.chainId, validated.contractAddress), validated);
377
- return validated;
378
158
  };
379
- var getCustomToken = (chainId, contractAddress) => tokenRegistry.get(tokenKey(chainId, contractAddress));
380
- var getAllCustomTokens = () => Array.from(tokenRegistry.values());
381
- var unregisterToken = (chainId, contractAddress) => tokenRegistry.delete(tokenKey(chainId, contractAddress));
382
- var isCustomToken = (chainId, contractAddress) => tokenRegistry.has(tokenKey(chainId, contractAddress));
383
159
 
384
160
  // src/data/tokens.ts
385
161
  var USDC_BASE = {
@@ -511,7 +287,9 @@ function getAllTokens() {
511
287
  return Object.values(TOKENS);
512
288
  }
513
289
  function getTokensBySymbol(symbol) {
514
- return getAllTokens().filter((t) => t.symbol.toUpperCase() === symbol.toUpperCase());
290
+ return getAllTokens().filter(
291
+ (t) => t.symbol.toUpperCase() === symbol.toUpperCase()
292
+ );
515
293
  }
516
294
  function getTokensByChain(chainId) {
517
295
  return getAllTokens().filter((t) => t.chainId === chainId);
@@ -535,63 +313,6 @@ function getWETHTokens() {
535
313
  return getTokensBySymbol("WETH");
536
314
  }
537
315
 
538
- // src/abi/erc20.ts
539
- var ERC20_ABI = [
540
- {
541
- type: "function",
542
- name: "transferWithAuthorization",
543
- stateMutability: "nonpayable",
544
- inputs: [
545
- { name: "from", type: "address" },
546
- { name: "to", type: "address" },
547
- { name: "amount", type: "uint256" },
548
- { name: "validAfter", type: "uint256" },
549
- { name: "expiry", type: "uint256" },
550
- { name: "v", type: "uint8" },
551
- { name: "r", type: "bytes32" },
552
- { name: "s", type: "bytes32" }
553
- ],
554
- outputs: []
555
- },
556
- {
557
- type: "function",
558
- name: "receiveWithAuthorization",
559
- stateMutability: "nonpayable",
560
- inputs: [
561
- { name: "from", type: "address" },
562
- { name: "to", type: "address" },
563
- { name: "amount", type: "uint256" },
564
- { name: "validAfter", type: "uint256" },
565
- { name: "expiry", type: "uint256" },
566
- { name: "v", type: "uint8" },
567
- { name: "r", type: "bytes32" },
568
- { name: "s", type: "bytes32" }
569
- ],
570
- outputs: []
571
- },
572
- {
573
- type: "function",
574
- name: "balanceOf",
575
- stateMutability: "view",
576
- inputs: [{ name: "account", type: "address" }],
577
- outputs: [{ name: "balance", type: "uint256" }]
578
- },
579
- {
580
- type: "function",
581
- name: "name",
582
- stateMutability: "view",
583
- inputs: [],
584
- outputs: [{ name: "", type: "string" }]
585
- },
586
- {
587
- type: "function",
588
- name: "symbol",
589
- stateMutability: "view",
590
- inputs: [],
591
- outputs: [{ name: "", type: "string" }]
592
- }
593
- ];
594
-
595
316
  // src/eip712.ts
596
317
  var EIP712_TYPES = {
597
318
  TransferWithAuthorization: [
@@ -621,20 +342,566 @@ var createTransferWithAuthorization = (params) => ({
621
342
  validBefore: BigInt(params.validBefore),
622
343
  nonce: params.nonce
623
344
  });
624
- var isAddress2 = (value) => /^0x[a-fA-F0-9]{40}$/.test(value);
345
+ var isAddress = (value) => /^0x[a-fA-F0-9]{40}$/.test(value);
625
346
  var isBytes32 = (value) => /^0x[a-fA-F0-9]{64}$/.test(value);
626
347
  var validateTransferWithAuthorization = (message) => {
627
- if (!isAddress2(message.from)) throw new Error(`Invalid "from" address: ${message.from}`);
628
- if (!isAddress2(message.to)) throw new Error(`Invalid "to" address: ${message.to}`);
629
- if (message.value < 0n) throw new Error(`"value" must be non-negative: ${message.value}`);
630
- if (message.validAfter < 0n) throw new Error(`"validAfter" must be non-negative: ${message.validAfter}`);
631
- if (message.validBefore < 0n) throw new Error(`"validBefore" must be non-negative: ${message.validBefore}`);
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
+ );
632
360
  if (message.validAfter >= message.validBefore) {
633
- throw new Error(`"validAfter" (${message.validAfter}) must be before "validBefore" (${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
+ };
371
+
372
+ // src/types/v2.ts
373
+ var V2_HEADERS = {
374
+ PAYMENT_SIGNATURE: "PAYMENT-SIGNATURE",
375
+ PAYMENT_REQUIRED: "PAYMENT-REQUIRED",
376
+ PAYMENT_RESPONSE: "PAYMENT-RESPONSE"
377
+ };
378
+ function isCAIP2ChainId(value) {
379
+ return /^eip155:\d+$/.test(value);
380
+ }
381
+ function isCAIPAssetId(value) {
382
+ return /^eip155:\d+\/erc20:0x[a-fA-F0-9]+$/.test(value);
383
+ }
384
+ function isAddress2(value) {
385
+ return /^0x[a-fA-F0-9]{40}$/.test(value);
386
+ }
387
+ function isPaymentRequiredV2(obj) {
388
+ return typeof obj === "object" && obj !== null && "x402Version" in obj && obj.x402Version === 2 && "resource" in obj && "accepts" in obj && Array.isArray(obj.accepts);
389
+ }
390
+ function isPaymentPayloadV2(obj) {
391
+ return typeof obj === "object" && obj !== null && "x402Version" in obj && obj.x402Version === 2 && "accepted" in obj && "payload" in obj;
392
+ }
393
+ function assetIdToAddress(assetId) {
394
+ const match = assetId.match(/\/erc20:(0x[a-fA-F0-9]{40})$/);
395
+ if (!match) throw new Error(`Invalid CAIP asset ID: ${assetId}`);
396
+ return match[1];
397
+ }
398
+ function addressToAssetId(address, chainId) {
399
+ const chain = typeof chainId === "number" ? `eip155:${chainId}` : chainId;
400
+ if (!isCAIP2ChainId(chain)) throw new Error(`Invalid chain ID: ${chain}`);
401
+ return `${chain}/erc20:${address}`;
402
+ }
403
+ function parseSignature(signature) {
404
+ const sig = signature.slice(2);
405
+ return {
406
+ r: `0x${sig.slice(0, 64)}`,
407
+ s: `0x${sig.slice(64, 128)}`,
408
+ v: parseInt(sig.slice(128, 130), 16)
409
+ };
410
+ }
411
+ function combineSignature(v, r, s) {
412
+ const rClean = r.startsWith("0x") ? r.slice(2) : r;
413
+ const sClean = s.startsWith("0x") ? s.slice(2) : s;
414
+ const vHex = v.toString(16).padStart(2, "0");
415
+ return `0x${rClean}${sClean}${vHex}`;
416
+ }
417
+
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");
430
+ }
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;
439
+ }
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));
489
+ }
490
+ function encodePayment(payload) {
491
+ if (!isPaymentPayload(payload)) {
492
+ throw new Error("Invalid payment payload format");
493
+ }
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));
503
+ }
504
+ function decodePayment(encoded) {
505
+ let parsed;
506
+ try {
507
+ parsed = JSON.parse(encoded);
508
+ } catch {
509
+ const decoded = safeBase64Decode2(encoded);
510
+ parsed = JSON.parse(decoded);
511
+ }
512
+ if (!isPaymentPayload(parsed)) {
513
+ throw new Error("Invalid payment payload format");
514
+ }
515
+ return parsed;
516
+ }
517
+ function encodeSettlementResponse(response) {
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));
527
+ }
528
+ function decodeSettlementResponse(encoded) {
529
+ try {
530
+ return JSON.parse(encoded);
531
+ } catch {
532
+ const decoded = safeBase64Decode2(encoded);
533
+ return JSON.parse(decoded);
534
+ }
535
+ }
536
+ function encodeX402Response(response) {
537
+ return safeBase64Encode2(JSON.stringify(response));
538
+ }
539
+ function decodeX402Response(encoded) {
540
+ try {
541
+ return JSON.parse(encoded);
542
+ } catch {
543
+ const decoded = safeBase64Decode2(encoded);
544
+ return JSON.parse(decoded);
545
+ }
546
+ }
547
+ function detectPaymentVersion(headers) {
548
+ if (headers.has("PAYMENT-SIGNATURE")) {
549
+ return 2;
550
+ }
551
+ return null;
552
+ }
553
+ function extractPaymentFromHeaders(headers) {
554
+ const encoded = headers.get("PAYMENT-SIGNATURE");
555
+ if (!encoded) return null;
556
+ try {
557
+ return decodePayment(encoded);
558
+ } catch {
559
+ return null;
560
+ }
561
+ }
562
+ function createPaymentRequiredHeaders(requirements, options) {
563
+ const accepts = Array.isArray(requirements) ? requirements : [requirements];
564
+ const response = {
565
+ x402Version: 2,
566
+ error: options?.error ?? "Payment required",
567
+ resource: options?.resource ?? { url: "", mimeType: "application/json" },
568
+ accepts,
569
+ extensions: options?.extensions ?? {}
570
+ };
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
+ }
580
+
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
+ }
589
+ };
590
+ var SigningError = class extends X402ClientError {
591
+ constructor(message, cause) {
592
+ super(`Signing failed: ${message}`, cause);
593
+ this.name = "SigningError";
594
+ }
595
+ };
596
+ var PaymentException = class extends X402ClientError {
597
+ constructor(message, cause) {
598
+ super(`Payment failed: ${message}`, cause);
599
+ this.name = "PaymentException";
600
+ }
601
+ };
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);
621
+ }
622
+ function resolveUrl(config) {
623
+ return config?.url ?? DEFAULT_FACILITATOR_URL;
624
+ }
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 };
630
+ }
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();
647
+ }
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();
664
+ }
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();
676
+ }
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);
681
+ }
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
+ }
722
+ }
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");
728
+ }
729
+
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"
742
+ },
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"
750
+ },
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"
758
+ },
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"
766
+ },
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"
782
+ }
783
+ };
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");
795
+ }
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;
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}`;
634
890
  }
635
- if (!isBytes32(message.nonce)) throw new Error(`"nonce" must be a valid bytes32 hex string: ${message.nonce}`);
636
- return true;
637
- };
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
+ }
638
905
 
639
906
  // src/validation.ts
640
907
  var isEvmAddress2 = (value) => /^0x[a-fA-F0-9]{40}$/.test(value);
@@ -648,7 +915,9 @@ var resolveNetwork = (input) => {
648
915
  if (typeof input === "object" && input !== null && "chainId" in input) {
649
916
  const config = input;
650
917
  if (!config.chainId || !config.usdcAddress || !config.caip2Id) {
651
- return createError("INVALID_CAIP_FORMAT", "Invalid network config", { value: config });
918
+ return createError("INVALID_CAIP_FORMAT", "Invalid network config", {
919
+ value: config
920
+ });
652
921
  }
653
922
  return {
654
923
  input,
@@ -660,11 +929,10 @@ var resolveNetwork = (input) => {
660
929
  const config = getNetworkByChainId(input);
661
930
  if (!config) {
662
931
  const validChainIds = Object.values(NETWORKS).map((n) => n.chainId);
663
- return createError(
664
- "UNKNOWN_NETWORK",
665
- `Unknown chain ID: ${input}`,
666
- { value: input, validOptions: validChainIds.map(String) }
667
- );
932
+ return createError("UNKNOWN_NETWORK", `Unknown chain ID: ${input}`, {
933
+ value: input,
934
+ validOptions: validChainIds.map(String)
935
+ });
668
936
  }
669
937
  return {
670
938
  input,
@@ -675,13 +943,21 @@ var resolveNetwork = (input) => {
675
943
  if (typeof input === "string") {
676
944
  if (input.startsWith("eip155:")) {
677
945
  const parts = input.split(":");
678
- if (parts.length !== 2 || isNaN(Number(parts[1]))) {
679
- 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
+ );
680
952
  }
681
953
  const chainId = Number(parts[1]);
682
954
  const config2 = getNetworkByChainId(chainId);
683
955
  if (!config2) {
684
- 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
+ );
685
961
  }
686
962
  return {
687
963
  input,
@@ -693,11 +969,10 @@ var resolveNetwork = (input) => {
693
969
  const config = getNetworkConfig(normalizedName);
694
970
  if (!config) {
695
971
  const validNames = Object.keys(NETWORKS);
696
- return createError(
697
- "UNKNOWN_NETWORK",
698
- `Unknown network: "${input}"`,
699
- { value: input, validOptions: validNames }
700
- );
972
+ return createError("UNKNOWN_NETWORK", `Unknown network: "${input}"`, {
973
+ value: input,
974
+ validOptions: validNames
975
+ });
701
976
  }
702
977
  return {
703
978
  input,
@@ -705,7 +980,11 @@ var resolveNetwork = (input) => {
705
980
  caip2: config.caip2Id
706
981
  };
707
982
  }
708
- 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
+ );
709
988
  };
710
989
  var getAvailableNetworks = () => Object.keys(NETWORKS);
711
990
  var normalizeTokenSymbol = (symbol) => symbol.toUpperCase();
@@ -713,7 +992,9 @@ var resolveToken = (input, network) => {
713
992
  if (typeof input === "object" && input !== null && "contractAddress" in input) {
714
993
  const config = input;
715
994
  if (!config.chainId || !config.contractAddress || !config.symbol) {
716
- return createError("VALIDATION_FAILED", "Invalid token config", { value: config });
995
+ return createError("VALIDATION_FAILED", "Invalid token config", {
996
+ value: config
997
+ });
717
998
  }
718
999
  if (network && config.chainId !== network.config.chainId) {
719
1000
  return createError(
@@ -738,7 +1019,10 @@ var resolveToken = (input, network) => {
738
1019
  if (isEvmAddress2(input)) {
739
1020
  const contractAddress = input;
740
1021
  if (network) {
741
- const customToken = getCustomToken(network.config.chainId, contractAddress);
1022
+ const customToken = getCustomToken(
1023
+ network.config.chainId,
1024
+ contractAddress
1025
+ );
742
1026
  const config = customToken || {
743
1027
  symbol: "CUSTOM",
744
1028
  name: "Custom Token",
@@ -765,590 +1049,324 @@ var resolveToken = (input, network) => {
765
1049
  return tokenNetwork;
766
1050
  }
767
1051
  const caipAsset = `eip155:${matchingToken2.chainId}/erc20:${contractAddress}`;
768
- return {
769
- input,
770
- config: matchingToken2,
771
- caipAsset,
772
- network: tokenNetwork
773
- };
774
- }
775
- return createError(
776
- "UNKNOWN_TOKEN",
777
- `Token address "${contractAddress}" not found in registry. Please specify a network.`,
778
- { value: input, validOptions: ["Specify network parameter"] }
779
- );
780
- }
781
- if (input.includes("/erc20:")) {
782
- const parts = input.split("/");
783
- if (parts.length !== 2) {
784
- return createError("INVALID_CAIP_FORMAT", `Invalid CAIP Asset ID format: ${input}`, { value: input });
785
- }
786
- const chainId = Number(parts[0].split(":")[1]);
787
- const contractAddress = parts[1].split(":")[1];
788
- const tokenNetwork = resolveNetwork(chainId);
789
- if ("code" in tokenNetwork) {
790
- return tokenNetwork;
791
- }
792
- const customToken = getCustomToken(chainId, contractAddress);
793
- const config = customToken || {
794
- symbol: "CUSTOM",
795
- name: "Custom Token",
796
- version: "1",
797
- chainId,
798
- contractAddress,
799
- decimals: 18
800
- };
801
- return {
802
- input,
803
- config,
804
- caipAsset: input,
805
- network: tokenNetwork
806
- };
807
- }
808
- const normalizedSymbol = normalizeTokenSymbol(input);
809
- if (network) {
810
- const customTokens2 = getAllCustomTokens();
811
- const matchingToken2 = customTokens2.find(
812
- (t) => t.symbol?.toUpperCase() === normalizedSymbol && t.chainId === network.config.chainId
813
- );
814
- if (matchingToken2) {
815
- return {
816
- input,
817
- config: matchingToken2,
818
- caipAsset: `eip155:${matchingToken2.chainId}/erc20:${matchingToken2.contractAddress}`,
819
- network
820
- };
821
- }
822
- return {
823
- input,
824
- config: {
825
- symbol: normalizedSymbol,
826
- name: network.config.name + " " + normalizedSymbol,
827
- version: "2",
828
- chainId: network.config.chainId,
829
- contractAddress: network.config.usdcAddress,
830
- decimals: 6
831
- },
832
- caipAsset: network.config.caipAssetId,
833
- network
834
- };
835
- }
836
- const customTokens = getAllCustomTokens();
837
- const matchingToken = customTokens.find((t) => t.symbol?.toUpperCase() === normalizedSymbol);
838
- if (matchingToken) {
839
- const tokenNetwork = resolveNetwork(matchingToken.chainId);
840
- if ("code" in tokenNetwork) {
841
- return tokenNetwork;
842
- }
843
- return {
844
- input,
845
- config: matchingToken,
846
- caipAsset: `eip155:${matchingToken.chainId}/erc20:${matchingToken.contractAddress}`,
847
- network: tokenNetwork
848
- };
849
- }
850
- const baseNetwork = resolveNetwork("base");
851
- if ("code" in baseNetwork) {
852
- return baseNetwork;
853
- }
854
- return {
855
- input,
856
- config: {
857
- symbol: normalizedSymbol,
858
- name: "USD Coin",
859
- version: "2",
860
- chainId: 8453,
861
- contractAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
862
- decimals: 6
863
- },
864
- caipAsset: baseNetwork.config.caipAssetId,
865
- network: baseNetwork
866
- };
867
- }
868
- return createError("UNKNOWN_TOKEN", `Invalid token identifier type: ${typeof input}`, { value: input });
869
- };
870
- var getAvailableTokens = () => {
871
- const customTokens = getAllCustomTokens();
872
- const symbols = new Set(customTokens.map((t) => t.symbol.toUpperCase()));
873
- return Array.from(symbols);
874
- };
875
- var resolveFacilitator = (input, supportedNetworks, supportedTokens) => {
876
- try {
877
- new URL(input.url);
878
- } catch {
879
- return createError("VALIDATION_FAILED", `Invalid facilitator URL: ${input.url}`, { value: input.url });
880
- }
881
- const networks = [];
882
- if (input.networks) {
883
- for (const network of input.networks) {
884
- const resolved = resolveNetwork(network);
885
- if ("code" in resolved) {
886
- return resolved;
887
- }
888
- networks.push(resolved);
889
- }
890
- } else if (supportedNetworks) {
891
- networks.push(...supportedNetworks);
892
- }
893
- const tokens = [];
894
- if (input.tokens) {
895
- for (const token of input.tokens) {
896
- for (const network of networks.length > 0 ? networks : supportedNetworks || []) {
897
- const resolved = resolveToken(token, network);
898
- if ("code" in resolved) {
899
- continue;
900
- }
901
- tokens.push(resolved);
902
- break;
903
- }
904
- }
905
- } else if (supportedTokens) {
906
- tokens.push(...supportedTokens);
907
- }
908
- return {
909
- input,
910
- url: input.url,
911
- networks,
912
- tokens
913
- };
914
- };
915
- var checkFacilitatorSupport = (facilitator, network, token) => {
916
- if (facilitator.networks.length > 0) {
917
- const networkSupported = facilitator.networks.some(
918
- (n) => n.config.chainId === network.config.chainId
919
- );
920
- if (!networkSupported) {
921
- const supportedNames = facilitator.networks.map((n) => n.config.name);
922
- return createError(
923
- "FACILITATOR_NO_NETWORK_SUPPORT",
924
- `Facilitator "${facilitator.url}" does not support network "${network.config.name}" (chain ${network.config.chainId}). Supported: ${supportedNames.join(", ")}`,
925
- {
926
- value: { facilitator: facilitator.url, network: network.config.name },
927
- validOptions: supportedNames
928
- }
929
- );
930
- }
931
- }
932
- if (facilitator.tokens.length > 0) {
933
- const tokenSupported = facilitator.tokens.some(
934
- (t) => t.config.contractAddress.toLowerCase() === token.config.contractAddress.toLowerCase() && t.network.config.chainId === token.network.config.chainId
935
- );
936
- if (!tokenSupported) {
937
- const supportedTokens = facilitator.tokens.map((t) => `${t.config.symbol} (${t.network.config.name})`);
938
- return createError(
939
- "FACILITATOR_NO_TOKEN_SUPPORT",
940
- `Facilitator "${facilitator.url}" does not support token "${token.config.symbol}" on "${token.network.config.name}". Supported: ${supportedTokens.join(", ")}`,
941
- {
942
- value: { facilitator: facilitator.url, token: token.config.symbol, network: token.network.config.name },
943
- validOptions: supportedTokens
944
- }
945
- );
946
- }
947
- }
948
- return { supported: true };
949
- };
950
- var validatePaymentConfig = (network, token, facilitators, payTo = "0x0000000000000000000000000000000000000000", amount = "1.0") => {
951
- const resolvedNetwork = resolveNetwork(network);
952
- if ("code" in resolvedNetwork) {
953
- return resolvedNetwork;
954
- }
955
- const resolvedToken = resolveToken(token, resolvedNetwork);
956
- if ("code" in resolvedToken) {
957
- return resolvedToken;
958
- }
959
- const resolvedFacilitators = [];
960
- if (facilitators) {
961
- const facilitatorArray = Array.isArray(facilitators) ? facilitators : [facilitators];
962
- for (const facilitator of facilitatorArray) {
963
- const resolved = resolveFacilitator(facilitator, [resolvedNetwork], [resolvedToken]);
964
- if ("code" in resolved) {
965
- return resolved;
966
- }
967
- const supportCheck = checkFacilitatorSupport(resolved, resolvedNetwork, resolvedToken);
968
- if ("code" in supportCheck) {
969
- return supportCheck;
970
- }
971
- resolvedFacilitators.push(resolved);
972
- }
973
- }
974
- return {
975
- network: resolvedNetwork,
976
- token: resolvedToken,
977
- facilitators: resolvedFacilitators,
978
- version: 2,
979
- payTo,
980
- amount
981
- };
982
- };
983
- var validateAcceptConfig = (options, payTo, amount) => {
984
- const { networks: networkInputs, tokens: tokenInputs, facilitators, version = 2 } = options;
985
- const networkIds = networkInputs?.length ? networkInputs : Object.keys(NETWORKS);
986
- const tokenIds = tokenInputs?.length ? tokenInputs : ["usdc"];
987
- const networks = [];
988
- for (const networkId of networkIds) {
989
- const resolved = resolveNetwork(networkId);
990
- if ("code" in resolved) {
991
- return { success: false, error: resolved };
992
- }
993
- networks.push(resolved);
994
- }
995
- const tokens = [];
996
- for (const tokenId of tokenIds) {
997
- let found = false;
998
- for (const network of networks) {
999
- const resolved = resolveToken(tokenId, network);
1000
- if ("code" in resolved) {
1001
- continue;
1052
+ return {
1053
+ input,
1054
+ config: matchingToken2,
1055
+ caipAsset,
1056
+ network: tokenNetwork
1057
+ };
1002
1058
  }
1003
- tokens.push(resolved);
1004
- found = true;
1005
- break;
1059
+ return createError(
1060
+ "UNKNOWN_TOKEN",
1061
+ `Token address "${contractAddress}" not found in registry. Please specify a network.`,
1062
+ { value: input, validOptions: ["Specify network parameter"] }
1063
+ );
1006
1064
  }
1007
- if (!found) {
1065
+ if (input.includes("/erc20:")) {
1066
+ const parts = input.split("/");
1067
+ if (parts.length !== 2) {
1068
+ return createError(
1069
+ "INVALID_CAIP_FORMAT",
1070
+ `Invalid CAIP Asset ID format: ${input}`,
1071
+ { value: input }
1072
+ );
1073
+ }
1074
+ const chainId = Number(parts[0].split(":")[1]);
1075
+ const contractAddress = parts[1].split(":")[1];
1076
+ const tokenNetwork = resolveNetwork(chainId);
1077
+ if ("code" in tokenNetwork) {
1078
+ return tokenNetwork;
1079
+ }
1080
+ const customToken = getCustomToken(chainId, contractAddress);
1081
+ const config = customToken || {
1082
+ symbol: "CUSTOM",
1083
+ name: "Custom Token",
1084
+ version: "1",
1085
+ chainId,
1086
+ contractAddress,
1087
+ decimals: 18
1088
+ };
1008
1089
  return {
1009
- success: false,
1010
- error: createError(
1011
- "TOKEN_NOT_ON_NETWORK",
1012
- `Token "${String(tokenId)}" not found on any of the specified networks`,
1013
- { value: tokenId, validOptions: networks.map((n) => n.config.name) }
1014
- )
1090
+ input,
1091
+ config,
1092
+ caipAsset: input,
1093
+ network: tokenNetwork
1015
1094
  };
1016
1095
  }
1017
- }
1018
- const facilitatorArray = facilitators ? Array.isArray(facilitators) ? facilitators : [facilitators] : [];
1019
- const resolvedFacilitators = [];
1020
- for (const facilitator of facilitatorArray) {
1021
- const resolved = resolveFacilitator(facilitator, networks, tokens);
1022
- if ("code" in resolved) {
1023
- return { success: false, error: resolved };
1024
- }
1025
- resolvedFacilitators.push(resolved);
1026
- }
1027
- const configs = [];
1028
- for (const network of networks) {
1029
- for (const token of tokens) {
1030
- if (token.network.config.chainId === network.config.chainId) {
1031
- configs.push({
1032
- network,
1033
- token,
1034
- facilitators: resolvedFacilitators,
1035
- version,
1036
- payTo,
1037
- amount
1038
- });
1096
+ const normalizedSymbol = normalizeTokenSymbol(input);
1097
+ if (network) {
1098
+ const customTokens2 = getAllCustomTokens();
1099
+ const matchingToken2 = customTokens2.find(
1100
+ (t) => t.symbol?.toUpperCase() === normalizedSymbol && t.chainId === network.config.chainId
1101
+ );
1102
+ if (matchingToken2) {
1103
+ return {
1104
+ input,
1105
+ config: matchingToken2,
1106
+ caipAsset: `eip155:${matchingToken2.chainId}/erc20:${matchingToken2.contractAddress}`,
1107
+ network
1108
+ };
1039
1109
  }
1110
+ return {
1111
+ input,
1112
+ config: {
1113
+ symbol: normalizedSymbol,
1114
+ name: `${network.config.name} ${normalizedSymbol}`,
1115
+ version: "2",
1116
+ chainId: network.config.chainId,
1117
+ contractAddress: network.config.usdcAddress,
1118
+ decimals: 6
1119
+ },
1120
+ caipAsset: network.config.caipAssetId,
1121
+ network
1122
+ };
1040
1123
  }
1041
- }
1042
- return { success: true, config: configs };
1043
- };
1044
- var isValidationError = (value) => {
1045
- return typeof value === "object" && value !== null && "code" in value;
1046
- };
1047
- var isResolvedNetwork = (value) => {
1048
- return typeof value === "object" && value !== null && "config" in value && "caip2" in value;
1049
- };
1050
- var isResolvedToken = (value) => {
1051
- return typeof value === "object" && value !== null && "config" in value && "caipAsset" in value;
1052
- };
1053
-
1054
- // src/utils/routes.ts
1055
- var PRIORITY_EXACT = 3;
1056
- var PRIORITY_PARAMETRIZED = 2;
1057
- var PRIORITY_WILDCARD = 1;
1058
- function parseRoutePattern(pattern) {
1059
- const normalizedPattern = pattern.startsWith("/") ? pattern : `/${pattern}`;
1060
- const segments = normalizedPattern.split("/").filter(Boolean);
1061
- let isWildcard = false;
1062
- let isParametrized = false;
1063
- const paramNames = [];
1064
- const seenParamNames = /* @__PURE__ */ new Set();
1065
- const recordParamName = (name) => {
1066
- if (!name) {
1067
- return;
1068
- }
1069
- if (seenParamNames.has(name)) {
1070
- return;
1071
- }
1072
- seenParamNames.add(name);
1073
- paramNames.push(name);
1074
- };
1075
- for (const segment of segments) {
1076
- if (segment === "*") {
1077
- isWildcard = true;
1078
- continue;
1079
- }
1080
- const hasWildcardToken = segment.includes("*");
1081
- if (segment.startsWith(":")) {
1082
- isParametrized = true;
1083
- const paramName = segment.replace(/\*+$/, "").slice(1);
1084
- recordParamName(paramName);
1085
- if (hasWildcardToken) {
1086
- isWildcard = true;
1124
+ const customTokens = getAllCustomTokens();
1125
+ const matchingToken = customTokens.find(
1126
+ (t) => t.symbol?.toUpperCase() === normalizedSymbol
1127
+ );
1128
+ if (matchingToken) {
1129
+ const tokenNetwork = resolveNetwork(matchingToken.chainId);
1130
+ if ("code" in tokenNetwork) {
1131
+ return tokenNetwork;
1087
1132
  }
1088
- continue;
1133
+ return {
1134
+ input,
1135
+ config: matchingToken,
1136
+ caipAsset: `eip155:${matchingToken.chainId}/erc20:${matchingToken.contractAddress}`,
1137
+ network: tokenNetwork
1138
+ };
1089
1139
  }
1090
- if (hasWildcardToken) {
1091
- const parts = segment.split("*");
1092
- for (const part of parts) {
1093
- if (part.startsWith(":")) {
1094
- isParametrized = true;
1095
- recordParamName(part.slice(1));
1096
- }
1097
- }
1098
- isWildcard = true;
1140
+ const baseNetwork = resolveNetwork("base");
1141
+ if ("code" in baseNetwork) {
1142
+ return baseNetwork;
1099
1143
  }
1144
+ return {
1145
+ input,
1146
+ config: {
1147
+ symbol: normalizedSymbol,
1148
+ name: "USD Coin",
1149
+ version: "2",
1150
+ chainId: 8453,
1151
+ contractAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
1152
+ decimals: 6
1153
+ },
1154
+ caipAsset: baseNetwork.config.caipAssetId,
1155
+ network: baseNetwork
1156
+ };
1100
1157
  }
1101
- let priority = PRIORITY_WILDCARD;
1102
- if (!isWildcard && !isParametrized) {
1103
- priority = PRIORITY_EXACT;
1104
- } else if (isParametrized && !isWildcard) {
1105
- priority = PRIORITY_PARAMETRIZED;
1106
- } else if (isParametrized && isWildcard) {
1107
- priority = PRIORITY_PARAMETRIZED;
1108
- }
1109
- return { segments, isWildcard, isParametrized, paramNames, priority };
1110
- }
1111
- function matchSegment(patternSegment, pathSegment) {
1112
- if (patternSegment === "*") {
1113
- return true;
1114
- }
1115
- if (patternSegment.startsWith(":")) {
1116
- return true;
1117
- }
1118
- if (patternSegment.includes("*")) {
1119
- const regex = new RegExp(
1120
- "^" + patternSegment.replace(/\*/g, ".*").replace(/:/g, "") + "$"
1158
+ return createError(
1159
+ "UNKNOWN_TOKEN",
1160
+ `Invalid token identifier type: ${typeof input}`,
1161
+ { value: input }
1162
+ );
1163
+ };
1164
+ var getAvailableTokens = () => {
1165
+ const customTokens = getAllCustomTokens();
1166
+ const symbols = new Set(customTokens.map((t) => t.symbol.toUpperCase()));
1167
+ return Array.from(symbols);
1168
+ };
1169
+ var resolveFacilitator = (input, supportedNetworks, supportedTokens) => {
1170
+ try {
1171
+ new URL(input.url);
1172
+ } catch {
1173
+ return createError(
1174
+ "VALIDATION_FAILED",
1175
+ `Invalid facilitator URL: ${input.url}`,
1176
+ { value: input.url }
1121
1177
  );
1122
- return regex.test(pathSegment);
1123
- }
1124
- return patternSegment === pathSegment;
1125
- }
1126
- function matchWildcardPattern(patternSegments, pathSegments) {
1127
- const requiredSegments = patternSegments.filter((s) => s !== "*");
1128
- if (requiredSegments.length > pathSegments.length) {
1129
- return false;
1130
- }
1131
- for (let i = 0; i < requiredSegments.length; i++) {
1132
- const patternIndex = patternSegments.indexOf(requiredSegments[i]);
1133
- if (pathSegments[patternIndex] !== requiredSegments[i].replace(/^\:/, "")) {
1134
- if (!requiredSegments[i].startsWith(":") && requiredSegments[i] !== "*") {
1135
- return false;
1136
- }
1137
- }
1138
- }
1139
- return true;
1140
- }
1141
- function matchRoute(pattern, path) {
1142
- const normalizedPattern = pattern.startsWith("/") ? pattern : `/${pattern}`;
1143
- const normalizedPath = path.startsWith("/") ? path : `/${path}`;
1144
- if (normalizedPattern === normalizedPath) {
1145
- return true;
1146
- }
1147
- const parsed = parseRoutePattern(normalizedPattern);
1148
- const patternSegments = parsed.segments;
1149
- const pathSegments = normalizedPath.split("/").filter(Boolean);
1150
- if (!parsed.isWildcard && patternSegments.length !== pathSegments.length) {
1151
- return false;
1152
- }
1153
- if (parsed.isWildcard && patternSegments.length > pathSegments.length + 1) {
1154
- return false;
1155
- }
1156
- if (parsed.isWildcard) {
1157
- return matchWildcardPattern(patternSegments, pathSegments);
1158
1178
  }
1159
- for (let i = 0; i < patternSegments.length; i++) {
1160
- if (!matchSegment(patternSegments[i], pathSegments[i])) {
1161
- return false;
1162
- }
1163
- }
1164
- return true;
1165
- }
1166
- function findMatchingRoute(routes, path) {
1167
- const matchingRoutes = [];
1168
- for (const route of routes) {
1169
- if (matchRoute(route.pattern, path)) {
1170
- const parsed = parseRoutePattern(route.pattern);
1171
- matchingRoutes.push({ route, parsed });
1179
+ const networks = [];
1180
+ if (input.networks) {
1181
+ for (const network of input.networks) {
1182
+ const resolved = resolveNetwork(network);
1183
+ if ("code" in resolved) {
1184
+ return resolved;
1185
+ }
1186
+ networks.push(resolved);
1172
1187
  }
1188
+ } else if (supportedNetworks) {
1189
+ networks.push(...supportedNetworks);
1173
1190
  }
1174
- if (matchingRoutes.length === 0) {
1175
- return null;
1191
+ const tokens = [];
1192
+ if (input.tokens) {
1193
+ for (const token of input.tokens) {
1194
+ for (const network of networks.length > 0 ? networks : supportedNetworks || []) {
1195
+ const resolved = resolveToken(token, network);
1196
+ if ("code" in resolved) {
1197
+ continue;
1198
+ }
1199
+ tokens.push(resolved);
1200
+ break;
1201
+ }
1202
+ }
1203
+ } else if (supportedTokens) {
1204
+ tokens.push(...supportedTokens);
1176
1205
  }
1177
- matchingRoutes.sort((a, b) => {
1178
- if (b.parsed.priority !== a.parsed.priority) {
1179
- return b.parsed.priority - a.parsed.priority;
1206
+ return {
1207
+ input,
1208
+ url: input.url,
1209
+ networks,
1210
+ tokens
1211
+ };
1212
+ };
1213
+ var checkFacilitatorSupport = (facilitator, network, token) => {
1214
+ if (facilitator.networks.length > 0) {
1215
+ const networkSupported = facilitator.networks.some(
1216
+ (n) => n.config.chainId === network.config.chainId
1217
+ );
1218
+ if (!networkSupported) {
1219
+ const supportedNames = facilitator.networks.map((n) => n.config.name);
1220
+ return createError(
1221
+ "FACILITATOR_NO_NETWORK_SUPPORT",
1222
+ `Facilitator "${facilitator.url}" does not support network "${network.config.name}" (chain ${network.config.chainId}). Supported: ${supportedNames.join(", ")}`,
1223
+ {
1224
+ value: { facilitator: facilitator.url, network: network.config.name },
1225
+ validOptions: supportedNames
1226
+ }
1227
+ );
1180
1228
  }
1181
- if (b.parsed.segments.length !== a.parsed.segments.length) {
1182
- return b.parsed.segments.length - a.parsed.segments.length;
1229
+ }
1230
+ if (facilitator.tokens.length > 0) {
1231
+ const tokenSupported = facilitator.tokens.some(
1232
+ (t) => t.config.contractAddress.toLowerCase() === token.config.contractAddress.toLowerCase() && t.network.config.chainId === token.network.config.chainId
1233
+ );
1234
+ if (!tokenSupported) {
1235
+ const supportedTokens = facilitator.tokens.map(
1236
+ (t) => `${t.config.symbol} (${t.network.config.name})`
1237
+ );
1238
+ return createError(
1239
+ "FACILITATOR_NO_TOKEN_SUPPORT",
1240
+ `Facilitator "${facilitator.url}" does not support token "${token.config.symbol}" on "${token.network.config.name}". Supported: ${supportedTokens.join(", ")}`,
1241
+ {
1242
+ value: {
1243
+ facilitator: facilitator.url,
1244
+ token: token.config.symbol,
1245
+ network: token.network.config.name
1246
+ },
1247
+ validOptions: supportedTokens
1248
+ }
1249
+ );
1183
1250
  }
1184
- return b.route.pattern.length - a.route.pattern.length;
1185
- });
1186
- return matchingRoutes[0].route;
1187
- }
1188
- function containsWildcard(pattern) {
1189
- return pattern.includes("*");
1190
- }
1191
- function validateRouteConfig(config) {
1192
- const { route, routes } = config;
1193
- if (!route && !routes) {
1194
- return null;
1195
1251
  }
1196
- if (route && routes) {
1197
- return {
1198
- code: "INVALID_ROUTE_CONFIG",
1199
- message: "Cannot specify both 'route' and 'routes'. Use 'route' for a single exact path or 'routes' for multiple paths.",
1200
- path: "route",
1201
- value: { route, routes }
1202
- };
1252
+ return { supported: true };
1253
+ };
1254
+ var validatePaymentConfig = (network, token, facilitators, payTo = "0x0000000000000000000000000000000000000000", amount = "1.0") => {
1255
+ const resolvedNetwork = resolveNetwork(network);
1256
+ if ("code" in resolvedNetwork) {
1257
+ return resolvedNetwork;
1203
1258
  }
1204
- if (route && containsWildcard(route)) {
1205
- return {
1206
- code: "INVALID_ROUTE_PATTERN",
1207
- message: `Wildcard routes must use the routes array, not 'route'. Use 'routes: ["/api/*"]' instead of 'route: "/api/*"'.`,
1208
- path: "route",
1209
- value: route,
1210
- validOptions: ['routes: ["/api/*"]', 'routes: ["/api/users", "/api/posts"]']
1211
- };
1259
+ const resolvedToken = resolveToken(token, resolvedNetwork);
1260
+ if ("code" in resolvedToken) {
1261
+ return resolvedToken;
1212
1262
  }
1213
- return null;
1214
- }
1215
-
1216
- // src/encoding.ts
1217
- function safeBase64Decode2(str) {
1218
- return decodeBase64ToUtf8(normalizeBase64Url(str));
1219
- }
1220
- function safeBase64Encode2(str) {
1221
- return toBase64Url(encodeUtf8ToBase64(str));
1222
- }
1223
- var base64JsonEncode = (data) => safeBase64Encode2(JSON.stringify(data));
1224
- var base64JsonDecode = (encoded) => JSON.parse(safeBase64Decode2(encoded));
1225
- var encodePaymentV2 = (payload) => base64JsonEncode(payload);
1226
- var decodePaymentV2 = (encoded) => base64JsonDecode(encoded);
1227
- var encodeSettlementV2 = (response) => base64JsonEncode(response);
1228
- var decodeSettlementV2 = (encoded) => base64JsonDecode(encoded);
1229
- var isPaymentV2 = (payload) => "x402Version" in payload && payload.x402Version === 2 && "accepted" in payload && "payload" in payload;
1230
- var isSettlementV2 = (response) => "success" in response && typeof response.success === "boolean" && "network" in response;
1231
-
1232
- // src/payment-client.ts
1233
- var DEFAULT_FACILITATOR_URL = "https://facilitator.payai.network";
1234
- function toJsonSafe(data) {
1235
- function convert(value) {
1236
- if (value !== null && typeof value === "object" && !Array.isArray(value)) {
1237
- return Object.fromEntries(Object.entries(value).map(([key, val]) => [key, convert(val)]));
1238
- }
1239
- if (Array.isArray(value)) {
1240
- return value.map(convert);
1241
- }
1242
- if (typeof value === "bigint") {
1243
- return value.toString();
1263
+ const resolvedFacilitators = [];
1264
+ if (facilitators) {
1265
+ const facilitatorArray = Array.isArray(facilitators) ? facilitators : [facilitators];
1266
+ for (const facilitator of facilitatorArray) {
1267
+ const resolved = resolveFacilitator(
1268
+ facilitator,
1269
+ [resolvedNetwork],
1270
+ [resolvedToken]
1271
+ );
1272
+ if ("code" in resolved) {
1273
+ return resolved;
1274
+ }
1275
+ const supportCheck = checkFacilitatorSupport(
1276
+ resolved,
1277
+ resolvedNetwork,
1278
+ resolvedToken
1279
+ );
1280
+ if ("code" in supportCheck) {
1281
+ return supportCheck;
1282
+ }
1283
+ resolvedFacilitators.push(resolved);
1244
1284
  }
1245
- return value;
1246
- }
1247
- return convert(data);
1248
- }
1249
- function resolveUrl(config) {
1250
- return config?.url ?? DEFAULT_FACILITATOR_URL;
1251
- }
1252
- async function resolveHeaders(config) {
1253
- const base = { "Content-Type": "application/json" };
1254
- if (!config?.createHeaders) return base;
1255
- const extra = await config.createHeaders();
1256
- return { ...base, ...extra };
1257
- }
1258
- async function verifyPayment(payload, requirements, config) {
1259
- const url = resolveUrl(config);
1260
- const headers = await resolveHeaders(config);
1261
- const response = await fetch(`${url}/verify`, {
1262
- method: "POST",
1263
- headers,
1264
- body: JSON.stringify({
1265
- paymentPayload: toJsonSafe(payload),
1266
- paymentRequirements: toJsonSafe(requirements)
1267
- })
1268
- });
1269
- if (response.status !== 200) {
1270
- const text = await response.text().catch(() => response.statusText);
1271
- throw new Error(`Facilitator verify failed: ${response.status} ${text}`);
1272
- }
1273
- return await response.json();
1274
- }
1275
- async function settlePayment(payload, requirements, config) {
1276
- const url = resolveUrl(config);
1277
- const headers = await resolveHeaders(config);
1278
- const response = await fetch(`${url}/settle`, {
1279
- method: "POST",
1280
- headers,
1281
- body: JSON.stringify({
1282
- paymentPayload: toJsonSafe(payload),
1283
- paymentRequirements: toJsonSafe(requirements)
1284
- })
1285
- });
1286
- if (response.status !== 200) {
1287
- const text = await response.text().catch(() => response.statusText);
1288
- throw new Error(`Facilitator settle failed: ${response.status} ${text}`);
1289
1285
  }
1290
- return await response.json();
1291
- }
1292
- async function getSupported(config) {
1293
- const url = resolveUrl(config);
1294
- const headers = await resolveHeaders(config);
1295
- const response = await fetch(`${url}/supported`, {
1296
- method: "GET",
1297
- headers
1298
- });
1299
- if (response.status !== 200) {
1300
- throw new Error(`Facilitator supported failed: ${response.statusText}`);
1286
+ return {
1287
+ network: resolvedNetwork,
1288
+ token: resolvedToken,
1289
+ facilitators: resolvedFacilitators,
1290
+ version: 2,
1291
+ payTo,
1292
+ amount
1293
+ };
1294
+ };
1295
+ var validateAcceptConfig = (options, payTo, amount) => {
1296
+ const {
1297
+ networks: networkInputs,
1298
+ tokens: tokenInputs,
1299
+ facilitators,
1300
+ version = 2
1301
+ } = options;
1302
+ const networkIds = networkInputs?.length ? networkInputs : Object.keys(NETWORKS);
1303
+ const tokenIds = tokenInputs?.length ? tokenInputs : ["usdc"];
1304
+ const networks = [];
1305
+ for (const networkId of networkIds) {
1306
+ const resolved = resolveNetwork(networkId);
1307
+ if ("code" in resolved) {
1308
+ return { success: false, error: resolved };
1309
+ }
1310
+ networks.push(resolved);
1301
1311
  }
1302
- return await response.json();
1303
- }
1304
- function isCompactV2Payload(payload) {
1305
- if (typeof payload !== "object" || payload === null) return false;
1306
- const record = payload;
1307
- return typeof record.x402Version === "number" && "payload" in record && !("accepted" in record);
1308
- }
1309
- function decodePayloadHeader(headerValue, defaults) {
1310
- if (headerValue.startsWith("{")) {
1311
- const parsed = JSON.parse(headerValue);
1312
- if (isPaymentPayload(parsed)) return parsed;
1313
- if (isCompactV2Payload(parsed)) {
1314
- const compact = parsed;
1315
- if (!defaults?.accepted) {
1316
- throw new Error("Invalid payment payload: missing 'accepted' field and no defaults provided");
1312
+ const tokens = [];
1313
+ for (const tokenId of tokenIds) {
1314
+ let found = false;
1315
+ for (const network of networks) {
1316
+ const resolved = resolveToken(tokenId, network);
1317
+ if ("code" in resolved) {
1318
+ continue;
1317
1319
  }
1320
+ tokens.push(resolved);
1321
+ found = true;
1322
+ break;
1323
+ }
1324
+ if (!found) {
1318
1325
  return {
1319
- x402Version: 2,
1320
- accepted: defaults.accepted,
1321
- payload: compact.payload
1326
+ success: false,
1327
+ error: createError(
1328
+ "TOKEN_NOT_ON_NETWORK",
1329
+ `Token "${String(tokenId)}" not found on any of the specified networks`,
1330
+ { value: tokenId, validOptions: networks.map((n) => n.config.name) }
1331
+ )
1322
1332
  };
1323
1333
  }
1324
- throw new Error("Invalid payment payload: unrecognized format");
1325
1334
  }
1326
- const normalized = headerValue.replace(/-/g, "+").replace(/_/g, "/").padEnd(Math.ceil(headerValue.length / 4) * 4, "=");
1327
- try {
1328
- const decoded = JSON.parse(decodeBase64ToUtf8(normalized));
1329
- if (isPaymentPayload(decoded)) return decoded;
1330
- if (isCompactV2Payload(decoded)) {
1331
- const compact = decoded;
1332
- if (!defaults?.accepted) {
1333
- throw new Error("Invalid payment payload: missing 'accepted' field and no defaults provided");
1335
+ const facilitatorArray = facilitators ? Array.isArray(facilitators) ? facilitators : [facilitators] : [];
1336
+ const resolvedFacilitators = [];
1337
+ for (const facilitator of facilitatorArray) {
1338
+ const resolved = resolveFacilitator(facilitator, networks, tokens);
1339
+ if ("code" in resolved) {
1340
+ return { success: false, error: resolved };
1341
+ }
1342
+ resolvedFacilitators.push(resolved);
1343
+ }
1344
+ const configs = [];
1345
+ for (const network of networks) {
1346
+ for (const token of tokens) {
1347
+ if (token.network.config.chainId === network.config.chainId) {
1348
+ configs.push({
1349
+ network,
1350
+ token,
1351
+ facilitators: resolvedFacilitators,
1352
+ version,
1353
+ payTo,
1354
+ amount
1355
+ });
1334
1356
  }
1335
- return {
1336
- x402Version: 2,
1337
- accepted: defaults.accepted,
1338
- payload: compact.payload
1339
- };
1340
1357
  }
1341
- throw new Error("Invalid payment payload: unrecognized format");
1342
- } catch {
1343
- throw new Error("Invalid payment payload: failed to decode");
1344
- }
1345
- }
1346
- function extractPayerAddress(payload) {
1347
- if (isExactEvmPayload(payload.payload)) {
1348
- return payload.payload.authorization.from;
1349
1358
  }
1350
- throw new Error("Unable to extract payer address from payload");
1351
- }
1359
+ return { success: true, config: configs };
1360
+ };
1361
+ var isValidationError = (value) => {
1362
+ return typeof value === "object" && value !== null && "code" in value;
1363
+ };
1364
+ var isResolvedNetwork = (value) => {
1365
+ return typeof value === "object" && value !== null && "config" in value && "caip2" in value;
1366
+ };
1367
+ var isResolvedToken = (value) => {
1368
+ return typeof value === "object" && value !== null && "config" in value && "caipAsset" in value;
1369
+ };
1352
1370
 
1353
1371
  // src/payment-requirements.ts
1354
1372
  var DEFAULT_NETWORKS = [
@@ -1391,7 +1409,9 @@ function resolvePayTo(config, network, token) {
1391
1409
  function resolveFacilitatorUrl(config, network, token) {
1392
1410
  const chainId = network.config.chainId;
1393
1411
  if (config.facilitatorUrlByToken) {
1394
- for (const [chainKey, tokenMap] of Object.entries(config.facilitatorUrlByToken)) {
1412
+ for (const [chainKey, tokenMap] of Object.entries(
1413
+ config.facilitatorUrlByToken
1414
+ )) {
1395
1415
  const resolvedChain = resolveNetwork(chainKey);
1396
1416
  if (!isValidationError2(resolvedChain) && resolvedChain.config.chainId === chainId) {
1397
1417
  for (const [tokenKey2, url] of Object.entries(tokenMap)) {
@@ -1404,7 +1424,9 @@ function resolveFacilitatorUrl(config, network, token) {
1404
1424
  }
1405
1425
  }
1406
1426
  if (config.facilitatorUrlByChain) {
1407
- for (const [chainKey, url] of Object.entries(config.facilitatorUrlByChain)) {
1427
+ for (const [chainKey, url] of Object.entries(
1428
+ config.facilitatorUrlByChain
1429
+ )) {
1408
1430
  const resolvedChain = resolveNetwork(chainKey);
1409
1431
  if (!isValidationError2(resolvedChain) && resolvedChain.config.chainId === chainId) {
1410
1432
  return url;
@@ -1463,7 +1485,11 @@ function createPaymentRequirements(config) {
1463
1485
  const atomicAmount = toAtomicUnits(amount);
1464
1486
  const tokenConfig = resolvedToken.config;
1465
1487
  const resolvedPayTo = resolvePayTo(config, network, resolvedToken);
1466
- resolveFacilitatorUrl(config, network, resolvedToken);
1488
+ resolveFacilitatorUrl(
1489
+ config,
1490
+ network,
1491
+ resolvedToken
1492
+ );
1467
1493
  const requirement = {
1468
1494
  scheme: "exact",
1469
1495
  network: network.caip2,
@@ -1497,28 +1523,6 @@ function findRequirementByNetwork(requirements, network) {
1497
1523
  return requirements.find((r) => r.network === netConfig.caip2Id);
1498
1524
  }
1499
1525
 
1500
- // src/errors.ts
1501
- var X402ClientError = class extends Error {
1502
- cause;
1503
- constructor(message, cause) {
1504
- super(message);
1505
- this.name = "X402ClientError";
1506
- this.cause = cause;
1507
- }
1508
- };
1509
- var SigningError = class extends X402ClientError {
1510
- constructor(message, cause) {
1511
- super(`Signing failed: ${message}`, cause);
1512
- this.name = "SigningError";
1513
- }
1514
- };
1515
- var PaymentException = class extends X402ClientError {
1516
- constructor(message, cause) {
1517
- super(`Payment failed: ${message}`, cause);
1518
- this.name = "PaymentException";
1519
- }
1520
- };
1521
-
1522
1526
  // src/protocol.ts
1523
1527
  function parseJsonOrBase64(value) {
1524
1528
  try {
@@ -1542,4 +1546,194 @@ function calculateValidBefore(expirySeconds = 3600) {
1542
1546
  return Math.floor(Date.now() / 1e3) + expirySeconds;
1543
1547
  }
1544
1548
 
1545
- 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, 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, findMatchingRoute, 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, 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, resolveNetwork, resolveToken, safeBase64Decode, safeBase64Encode, settlePayment, toAtomicUnits, toBase64Url, unregisterToken, validateAcceptConfig, validatePaymentConfig, validateRouteConfig, validateTransferWithAuthorization, verifyPayment };
1549
+ // src/types/protocol.ts
1550
+ function isX402V2Payload(obj) {
1551
+ return typeof obj === "object" && obj !== null && "x402Version" in obj && obj.x402Version === 2 && "accepted" in obj && "payload" in obj;
1552
+ }
1553
+ function isX402V2Requirements(obj) {
1554
+ 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
1555
+ "amount" in obj && "asset" in obj && "payTo" in obj && "maxTimeoutSeconds" in obj;
1556
+ }
1557
+ function isX402V2Settlement(obj) {
1558
+ return typeof obj === "object" && obj !== null && "success" in obj && typeof obj.success === "boolean" && "network" in obj && typeof obj.network === "string" && obj.network.startsWith("eip155:");
1559
+ }
1560
+ function isX402V2PaymentRequired(obj) {
1561
+ return typeof obj === "object" && obj !== null && "x402Version" in obj && obj.x402Version === 2 && "resource" in obj && "accepts" in obj;
1562
+ }
1563
+ var PAYMENT_SIGNATURE_HEADER = "PAYMENT-SIGNATURE";
1564
+ var PAYMENT_RESPONSE_HEADER = "PAYMENT-RESPONSE";
1565
+ var PAYMENT_REQUIRED_HEADER = "PAYMENT-REQUIRED";
1566
+ function isSettlementSuccessful(response) {
1567
+ return "success" in response ? response.success : false;
1568
+ }
1569
+ function getTxHash(response) {
1570
+ if ("transaction" in response) return response.transaction;
1571
+ return void 0;
1572
+ }
1573
+
1574
+ // src/utils/routes.ts
1575
+ var PRIORITY_EXACT = 3;
1576
+ var PRIORITY_PARAMETRIZED = 2;
1577
+ var PRIORITY_WILDCARD = 1;
1578
+ function parseRoutePattern(pattern) {
1579
+ const normalizedPattern = pattern.startsWith("/") ? pattern : `/${pattern}`;
1580
+ const segments = normalizedPattern.split("/").filter(Boolean);
1581
+ let isWildcard = false;
1582
+ let isParametrized = false;
1583
+ const paramNames = [];
1584
+ const seenParamNames = /* @__PURE__ */ new Set();
1585
+ const recordParamName = (name) => {
1586
+ if (!name) {
1587
+ return;
1588
+ }
1589
+ if (seenParamNames.has(name)) {
1590
+ return;
1591
+ }
1592
+ seenParamNames.add(name);
1593
+ paramNames.push(name);
1594
+ };
1595
+ for (const segment of segments) {
1596
+ if (segment === "*") {
1597
+ isWildcard = true;
1598
+ continue;
1599
+ }
1600
+ const hasWildcardToken = segment.includes("*");
1601
+ if (segment.startsWith(":")) {
1602
+ isParametrized = true;
1603
+ const paramName = segment.replace(/\*+$/, "").slice(1);
1604
+ recordParamName(paramName);
1605
+ if (hasWildcardToken) {
1606
+ isWildcard = true;
1607
+ }
1608
+ continue;
1609
+ }
1610
+ if (hasWildcardToken) {
1611
+ const parts = segment.split("*");
1612
+ for (const part of parts) {
1613
+ if (part.startsWith(":")) {
1614
+ isParametrized = true;
1615
+ recordParamName(part.slice(1));
1616
+ }
1617
+ }
1618
+ isWildcard = true;
1619
+ }
1620
+ }
1621
+ let priority = PRIORITY_WILDCARD;
1622
+ if (!isWildcard && !isParametrized) {
1623
+ priority = PRIORITY_EXACT;
1624
+ } else if (isParametrized && !isWildcard) {
1625
+ priority = PRIORITY_PARAMETRIZED;
1626
+ } else if (isParametrized && isWildcard) {
1627
+ priority = PRIORITY_PARAMETRIZED;
1628
+ }
1629
+ return { segments, isWildcard, isParametrized, paramNames, priority };
1630
+ }
1631
+ function matchSegment(patternSegment, pathSegment) {
1632
+ if (patternSegment === "*") {
1633
+ return true;
1634
+ }
1635
+ if (patternSegment.startsWith(":")) {
1636
+ return true;
1637
+ }
1638
+ if (patternSegment.includes("*")) {
1639
+ const regex = new RegExp(
1640
+ `^${patternSegment.replace(/\*/g, ".*").replace(/:/g, "")}$`
1641
+ );
1642
+ return regex.test(pathSegment);
1643
+ }
1644
+ return patternSegment === pathSegment;
1645
+ }
1646
+ function matchWildcardPattern(patternSegments, pathSegments) {
1647
+ const requiredSegments = patternSegments.filter((s) => s !== "*");
1648
+ if (requiredSegments.length > pathSegments.length) {
1649
+ return false;
1650
+ }
1651
+ for (let i = 0; i < requiredSegments.length; i++) {
1652
+ const patternIndex = patternSegments.indexOf(requiredSegments[i]);
1653
+ if (pathSegments[patternIndex] !== requiredSegments[i].replace(/^:/, "")) {
1654
+ if (!requiredSegments[i].startsWith(":") && requiredSegments[i] !== "*") {
1655
+ return false;
1656
+ }
1657
+ }
1658
+ }
1659
+ return true;
1660
+ }
1661
+ function matchRoute(pattern, path) {
1662
+ const normalizedPattern = pattern.startsWith("/") ? pattern : `/${pattern}`;
1663
+ const normalizedPath = path.startsWith("/") ? path : `/${path}`;
1664
+ if (normalizedPattern === normalizedPath) {
1665
+ return true;
1666
+ }
1667
+ const parsed = parseRoutePattern(normalizedPattern);
1668
+ const patternSegments = parsed.segments;
1669
+ const pathSegments = normalizedPath.split("/").filter(Boolean);
1670
+ if (!parsed.isWildcard && patternSegments.length !== pathSegments.length) {
1671
+ return false;
1672
+ }
1673
+ if (parsed.isWildcard && patternSegments.length > pathSegments.length + 1) {
1674
+ return false;
1675
+ }
1676
+ if (parsed.isWildcard) {
1677
+ return matchWildcardPattern(patternSegments, pathSegments);
1678
+ }
1679
+ for (let i = 0; i < patternSegments.length; i++) {
1680
+ if (!matchSegment(patternSegments[i], pathSegments[i])) {
1681
+ return false;
1682
+ }
1683
+ }
1684
+ return true;
1685
+ }
1686
+ function findMatchingRoute(routes, path) {
1687
+ const matchingRoutes = [];
1688
+ for (const route of routes) {
1689
+ if (matchRoute(route.pattern, path)) {
1690
+ const parsed = parseRoutePattern(route.pattern);
1691
+ matchingRoutes.push({ route, parsed });
1692
+ }
1693
+ }
1694
+ if (matchingRoutes.length === 0) {
1695
+ return null;
1696
+ }
1697
+ matchingRoutes.sort((a, b) => {
1698
+ if (b.parsed.priority !== a.parsed.priority) {
1699
+ return b.parsed.priority - a.parsed.priority;
1700
+ }
1701
+ if (b.parsed.segments.length !== a.parsed.segments.length) {
1702
+ return b.parsed.segments.length - a.parsed.segments.length;
1703
+ }
1704
+ return b.route.pattern.length - a.route.pattern.length;
1705
+ });
1706
+ return matchingRoutes[0].route;
1707
+ }
1708
+ function containsWildcard(pattern) {
1709
+ return pattern.includes("*");
1710
+ }
1711
+ function validateRouteConfig(config) {
1712
+ const { route, routes } = config;
1713
+ if (!route && !routes) {
1714
+ return null;
1715
+ }
1716
+ if (route && routes) {
1717
+ return {
1718
+ code: "INVALID_ROUTE_CONFIG",
1719
+ message: "Cannot specify both 'route' and 'routes'. Use 'route' for a single exact path or 'routes' for multiple paths.",
1720
+ path: "route",
1721
+ value: { route, routes }
1722
+ };
1723
+ }
1724
+ if (route && containsWildcard(route)) {
1725
+ return {
1726
+ code: "INVALID_ROUTE_PATTERN",
1727
+ message: `Wildcard routes must use the routes array, not 'route'. Use 'routes: ["/api/*"]' instead of 'route: "/api/*"'.`,
1728
+ path: "route",
1729
+ value: route,
1730
+ validOptions: [
1731
+ 'routes: ["/api/*"]',
1732
+ 'routes: ["/api/users", "/api/posts"]'
1733
+ ]
1734
+ };
1735
+ }
1736
+ return null;
1737
+ }
1738
+
1739
+ 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, 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, findMatchingRoute, 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, resolveNetwork, resolveToken, runAfterPaymentResponseHooks, runBeforeSignPaymentHooks, runOnPaymentRequiredHooks, safeBase64Decode2 as safeBase64Decode, safeBase64Encode2 as safeBase64Encode, selectRequirementWithHooks, settlePayment, toAtomicUnits, toBase64Url, unregisterToken, validateAcceptConfig, validatePaymentConfig, validateRouteConfig, validateTransferWithAuthorization, verifyPayment };