uvd-x402-sdk 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +782 -0
  3. package/dist/index-BrBqP1I8.d.ts +199 -0
  4. package/dist/index-D6Sr4ARD.d.mts +429 -0
  5. package/dist/index-D6Sr4ARD.d.ts +429 -0
  6. package/dist/index-DJ4Cvrev.d.mts +199 -0
  7. package/dist/index.d.mts +3 -0
  8. package/dist/index.d.ts +3 -0
  9. package/dist/index.js +1178 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/index.mjs +1146 -0
  12. package/dist/index.mjs.map +1 -0
  13. package/dist/providers/evm/index.d.mts +84 -0
  14. package/dist/providers/evm/index.d.ts +84 -0
  15. package/dist/providers/evm/index.js +740 -0
  16. package/dist/providers/evm/index.js.map +1 -0
  17. package/dist/providers/evm/index.mjs +735 -0
  18. package/dist/providers/evm/index.mjs.map +1 -0
  19. package/dist/providers/near/index.d.mts +99 -0
  20. package/dist/providers/near/index.d.ts +99 -0
  21. package/dist/providers/near/index.js +483 -0
  22. package/dist/providers/near/index.js.map +1 -0
  23. package/dist/providers/near/index.mjs +478 -0
  24. package/dist/providers/near/index.mjs.map +1 -0
  25. package/dist/providers/solana/index.d.mts +115 -0
  26. package/dist/providers/solana/index.d.ts +115 -0
  27. package/dist/providers/solana/index.js +771 -0
  28. package/dist/providers/solana/index.js.map +1 -0
  29. package/dist/providers/solana/index.mjs +765 -0
  30. package/dist/providers/solana/index.mjs.map +1 -0
  31. package/dist/providers/stellar/index.d.mts +67 -0
  32. package/dist/providers/stellar/index.d.ts +67 -0
  33. package/dist/providers/stellar/index.js +306 -0
  34. package/dist/providers/stellar/index.js.map +1 -0
  35. package/dist/providers/stellar/index.mjs +301 -0
  36. package/dist/providers/stellar/index.mjs.map +1 -0
  37. package/dist/react/index.d.mts +73 -0
  38. package/dist/react/index.d.ts +73 -0
  39. package/dist/react/index.js +1218 -0
  40. package/dist/react/index.js.map +1 -0
  41. package/dist/react/index.mjs +1211 -0
  42. package/dist/react/index.mjs.map +1 -0
  43. package/dist/utils/index.d.mts +103 -0
  44. package/dist/utils/index.d.ts +103 -0
  45. package/dist/utils/index.js +575 -0
  46. package/dist/utils/index.js.map +1 -0
  47. package/dist/utils/index.mjs +562 -0
  48. package/dist/utils/index.mjs.map +1 -0
  49. package/package.json +149 -0
  50. package/src/chains/index.ts +539 -0
  51. package/src/client/X402Client.ts +663 -0
  52. package/src/client/index.ts +1 -0
  53. package/src/index.ts +166 -0
  54. package/src/providers/evm/index.ts +394 -0
  55. package/src/providers/near/index.ts +664 -0
  56. package/src/providers/solana/index.ts +489 -0
  57. package/src/providers/stellar/index.ts +376 -0
  58. package/src/react/index.tsx +417 -0
  59. package/src/types/index.ts +561 -0
  60. package/src/utils/index.ts +20 -0
  61. package/src/utils/x402.ts +295 -0
package/dist/index.js ADDED
@@ -0,0 +1,1178 @@
1
+ 'use strict';
2
+
3
+ var ethers = require('ethers');
4
+
5
+ // src/client/X402Client.ts
6
+
7
+ // src/types/index.ts
8
+ var CAIP2_IDENTIFIERS = {
9
+ // EVM chains
10
+ base: "eip155:8453",
11
+ ethereum: "eip155:1",
12
+ polygon: "eip155:137",
13
+ arbitrum: "eip155:42161",
14
+ optimism: "eip155:10",
15
+ avalanche: "eip155:43114",
16
+ celo: "eip155:42220",
17
+ hyperevm: "eip155:999",
18
+ unichain: "eip155:130",
19
+ monad: "eip155:143",
20
+ bsc: "eip155:56",
21
+ // SVM chains
22
+ solana: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
23
+ fogo: "svm:fogo",
24
+ // Stellar
25
+ stellar: "stellar:pubnet",
26
+ // NEAR
27
+ near: "near:mainnet"
28
+ };
29
+ var CAIP2_TO_CHAIN = Object.fromEntries(
30
+ Object.entries(CAIP2_IDENTIFIERS).map(([k, v]) => [v, k])
31
+ );
32
+ var DEFAULT_CONFIG = {
33
+ facilitatorUrl: "https://facilitator.ultravioletadao.xyz",
34
+ defaultChain: "base",
35
+ autoConnect: false,
36
+ debug: false,
37
+ x402Version: "auto"
38
+ };
39
+ var X402Error = class _X402Error extends Error {
40
+ code;
41
+ details;
42
+ constructor(message, code, details) {
43
+ super(message);
44
+ this.name = "X402Error";
45
+ this.code = code;
46
+ this.details = details;
47
+ if (Error.captureStackTrace) {
48
+ Error.captureStackTrace(this, _X402Error);
49
+ }
50
+ }
51
+ };
52
+
53
+ // src/chains/index.ts
54
+ var DEFAULT_FACILITATOR_URL = "https://facilitator.ultravioletadao.xyz";
55
+ var SUPPORTED_CHAINS = {
56
+ // ============================================================================
57
+ // EVM CHAINS (11 networks)
58
+ // ============================================================================
59
+ base: {
60
+ chainId: 8453,
61
+ chainIdHex: "0x2105",
62
+ name: "base",
63
+ displayName: "Base",
64
+ networkType: "evm",
65
+ rpcUrl: "https://mainnet.base.org",
66
+ explorerUrl: "https://basescan.org",
67
+ nativeCurrency: {
68
+ name: "Ethereum",
69
+ symbol: "ETH",
70
+ decimals: 18
71
+ },
72
+ usdc: {
73
+ address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
74
+ decimals: 6,
75
+ name: "USD Coin",
76
+ version: "2"
77
+ },
78
+ x402: {
79
+ facilitatorUrl: DEFAULT_FACILITATOR_URL,
80
+ enabled: true
81
+ }
82
+ },
83
+ avalanche: {
84
+ chainId: 43114,
85
+ chainIdHex: "0xa86a",
86
+ name: "avalanche",
87
+ displayName: "Avalanche C-Chain",
88
+ networkType: "evm",
89
+ rpcUrl: "https://avalanche-c-chain-rpc.publicnode.com",
90
+ explorerUrl: "https://snowtrace.io",
91
+ nativeCurrency: {
92
+ name: "Avalanche",
93
+ symbol: "AVAX",
94
+ decimals: 18
95
+ },
96
+ usdc: {
97
+ address: "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
98
+ decimals: 6,
99
+ name: "USD Coin",
100
+ version: "2"
101
+ },
102
+ x402: {
103
+ facilitatorUrl: DEFAULT_FACILITATOR_URL,
104
+ enabled: true
105
+ }
106
+ },
107
+ ethereum: {
108
+ chainId: 1,
109
+ chainIdHex: "0x1",
110
+ name: "ethereum",
111
+ displayName: "Ethereum",
112
+ networkType: "evm",
113
+ rpcUrl: "https://eth.llamarpc.com",
114
+ explorerUrl: "https://etherscan.io",
115
+ nativeCurrency: {
116
+ name: "Ethereum",
117
+ symbol: "ETH",
118
+ decimals: 18
119
+ },
120
+ usdc: {
121
+ address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
122
+ decimals: 6,
123
+ name: "USD Coin",
124
+ version: "2"
125
+ },
126
+ x402: {
127
+ facilitatorUrl: DEFAULT_FACILITATOR_URL,
128
+ enabled: true
129
+ }
130
+ },
131
+ polygon: {
132
+ chainId: 137,
133
+ chainIdHex: "0x89",
134
+ name: "polygon",
135
+ displayName: "Polygon",
136
+ networkType: "evm",
137
+ rpcUrl: "https://polygon-rpc.com",
138
+ explorerUrl: "https://polygonscan.com",
139
+ nativeCurrency: {
140
+ name: "Polygon",
141
+ symbol: "POL",
142
+ decimals: 18
143
+ },
144
+ usdc: {
145
+ address: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
146
+ decimals: 6,
147
+ name: "USD Coin",
148
+ version: "2"
149
+ },
150
+ x402: {
151
+ facilitatorUrl: DEFAULT_FACILITATOR_URL,
152
+ enabled: true
153
+ }
154
+ },
155
+ arbitrum: {
156
+ chainId: 42161,
157
+ chainIdHex: "0xa4b1",
158
+ name: "arbitrum",
159
+ displayName: "Arbitrum One",
160
+ networkType: "evm",
161
+ rpcUrl: "https://arb1.arbitrum.io/rpc",
162
+ explorerUrl: "https://arbiscan.io",
163
+ nativeCurrency: {
164
+ name: "Ethereum",
165
+ symbol: "ETH",
166
+ decimals: 18
167
+ },
168
+ usdc: {
169
+ address: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
170
+ decimals: 6,
171
+ name: "USD Coin",
172
+ version: "2"
173
+ },
174
+ x402: {
175
+ facilitatorUrl: DEFAULT_FACILITATOR_URL,
176
+ enabled: true
177
+ }
178
+ },
179
+ optimism: {
180
+ chainId: 10,
181
+ chainIdHex: "0xa",
182
+ name: "optimism",
183
+ displayName: "Optimism",
184
+ networkType: "evm",
185
+ rpcUrl: "https://mainnet.optimism.io",
186
+ explorerUrl: "https://optimistic.etherscan.io",
187
+ nativeCurrency: {
188
+ name: "Ethereum",
189
+ symbol: "ETH",
190
+ decimals: 18
191
+ },
192
+ usdc: {
193
+ address: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
194
+ decimals: 6,
195
+ name: "USD Coin",
196
+ version: "2"
197
+ },
198
+ x402: {
199
+ facilitatorUrl: DEFAULT_FACILITATOR_URL,
200
+ enabled: true
201
+ }
202
+ },
203
+ celo: {
204
+ chainId: 42220,
205
+ chainIdHex: "0xa4ec",
206
+ name: "celo",
207
+ displayName: "Celo",
208
+ networkType: "evm",
209
+ rpcUrl: "https://forno.celo.org",
210
+ explorerUrl: "https://celoscan.io",
211
+ nativeCurrency: {
212
+ name: "Celo",
213
+ symbol: "CELO",
214
+ decimals: 18
215
+ },
216
+ usdc: {
217
+ address: "0xcebA9300f2b948710d2653dD7B07f33A8B32118C",
218
+ decimals: 6,
219
+ name: "USDC",
220
+ // Celo uses "USDC" not "USD Coin" for EIP-712
221
+ version: "2"
222
+ },
223
+ x402: {
224
+ facilitatorUrl: DEFAULT_FACILITATOR_URL,
225
+ enabled: true
226
+ }
227
+ },
228
+ hyperevm: {
229
+ chainId: 999,
230
+ chainIdHex: "0x3e7",
231
+ name: "hyperevm",
232
+ displayName: "HyperEVM",
233
+ networkType: "evm",
234
+ rpcUrl: "https://rpc.hyperliquid.xyz/evm",
235
+ explorerUrl: "https://hyperevmscan.io",
236
+ nativeCurrency: {
237
+ name: "Ethereum",
238
+ symbol: "ETH",
239
+ decimals: 18
240
+ },
241
+ usdc: {
242
+ address: "0xb88339CB7199b77E23DB6E890353E22632Ba630f",
243
+ decimals: 6,
244
+ name: "USDC",
245
+ // HyperEVM uses "USDC" not "USD Coin"
246
+ version: "2"
247
+ },
248
+ x402: {
249
+ facilitatorUrl: DEFAULT_FACILITATOR_URL,
250
+ enabled: true
251
+ }
252
+ },
253
+ unichain: {
254
+ chainId: 130,
255
+ chainIdHex: "0x82",
256
+ name: "unichain",
257
+ displayName: "Unichain",
258
+ networkType: "evm",
259
+ rpcUrl: "https://unichain-rpc.publicnode.com",
260
+ explorerUrl: "https://uniscan.xyz",
261
+ nativeCurrency: {
262
+ name: "Ethereum",
263
+ symbol: "ETH",
264
+ decimals: 18
265
+ },
266
+ usdc: {
267
+ address: "0x078d782b760474a361dda0af3839290b0ef57ad6",
268
+ decimals: 6,
269
+ name: "USDC",
270
+ // Unichain uses "USDC" not "USD Coin"
271
+ version: "2"
272
+ },
273
+ x402: {
274
+ facilitatorUrl: DEFAULT_FACILITATOR_URL,
275
+ enabled: true
276
+ }
277
+ },
278
+ monad: {
279
+ chainId: 143,
280
+ chainIdHex: "0x8f",
281
+ name: "monad",
282
+ displayName: "Monad",
283
+ networkType: "evm",
284
+ rpcUrl: "https://rpc.monad.xyz",
285
+ explorerUrl: "https://monad.socialscan.io",
286
+ nativeCurrency: {
287
+ name: "Monad",
288
+ symbol: "MON",
289
+ decimals: 18
290
+ },
291
+ usdc: {
292
+ address: "0x754704bc059f8c67012fed69bc8a327a5aafb603",
293
+ decimals: 6,
294
+ name: "USDC",
295
+ // Monad uses "USDC" not "USD Coin"
296
+ version: "2"
297
+ },
298
+ x402: {
299
+ facilitatorUrl: DEFAULT_FACILITATOR_URL,
300
+ enabled: true
301
+ }
302
+ },
303
+ // BSC disabled: USDC doesn't support ERC-3009 transferWithAuthorization
304
+ bsc: {
305
+ chainId: 56,
306
+ chainIdHex: "0x38",
307
+ name: "bsc",
308
+ displayName: "BNB Smart Chain",
309
+ networkType: "evm",
310
+ rpcUrl: "https://binance.llamarpc.com",
311
+ explorerUrl: "https://bscscan.com",
312
+ nativeCurrency: {
313
+ name: "Binance Coin",
314
+ symbol: "BNB",
315
+ decimals: 18
316
+ },
317
+ usdc: {
318
+ address: "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d",
319
+ decimals: 18,
320
+ // BSC USDC uses 18 decimals
321
+ name: "USD Coin",
322
+ version: "2"
323
+ },
324
+ x402: {
325
+ facilitatorUrl: DEFAULT_FACILITATOR_URL,
326
+ enabled: false
327
+ // Disabled: BSC USDC doesn't support ERC-3009
328
+ }
329
+ },
330
+ // ============================================================================
331
+ // SVM CHAINS (2 networks) - Solana Virtual Machine
332
+ // ============================================================================
333
+ solana: {
334
+ chainId: 0,
335
+ // Non-EVM
336
+ chainIdHex: "0x0",
337
+ name: "solana",
338
+ displayName: "Solana",
339
+ networkType: "svm",
340
+ rpcUrl: "https://api.mainnet-beta.solana.com",
341
+ explorerUrl: "https://solscan.io",
342
+ nativeCurrency: {
343
+ name: "Solana",
344
+ symbol: "SOL",
345
+ decimals: 9
346
+ },
347
+ usdc: {
348
+ address: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
349
+ // USDC SPL token mint
350
+ decimals: 6,
351
+ name: "USD Coin",
352
+ version: "1"
353
+ },
354
+ x402: {
355
+ facilitatorUrl: DEFAULT_FACILITATOR_URL,
356
+ enabled: true
357
+ }
358
+ },
359
+ fogo: {
360
+ chainId: 0,
361
+ // Non-EVM (SVM)
362
+ chainIdHex: "0x0",
363
+ name: "fogo",
364
+ displayName: "Fogo",
365
+ networkType: "svm",
366
+ rpcUrl: "https://rpc.fogo.nightly.app/",
367
+ explorerUrl: "https://explorer.fogo.nightly.app",
368
+ nativeCurrency: {
369
+ name: "Fogo",
370
+ symbol: "FOGO",
371
+ decimals: 9
372
+ },
373
+ usdc: {
374
+ address: "uSd2czE61Evaf76RNbq4KPpXnkiL3irdzgLFUMe3NoG",
375
+ // Fogo USDC mint
376
+ decimals: 6,
377
+ name: "USDC",
378
+ version: "1"
379
+ },
380
+ x402: {
381
+ facilitatorUrl: DEFAULT_FACILITATOR_URL,
382
+ enabled: true
383
+ }
384
+ },
385
+ // ============================================================================
386
+ // STELLAR (1 network)
387
+ // ============================================================================
388
+ stellar: {
389
+ chainId: 0,
390
+ // Non-EVM
391
+ chainIdHex: "0x0",
392
+ name: "stellar",
393
+ displayName: "Stellar",
394
+ networkType: "stellar",
395
+ rpcUrl: "https://horizon.stellar.org",
396
+ explorerUrl: "https://stellar.expert/explorer/public",
397
+ nativeCurrency: {
398
+ name: "Lumens",
399
+ symbol: "XLM",
400
+ decimals: 7
401
+ // Stellar uses 7 decimals (stroops)
402
+ },
403
+ usdc: {
404
+ address: "CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75",
405
+ // Soroban Asset Contract
406
+ decimals: 7,
407
+ // Stellar USDC uses 7 decimals
408
+ name: "USDC",
409
+ version: "1"
410
+ },
411
+ x402: {
412
+ facilitatorUrl: DEFAULT_FACILITATOR_URL,
413
+ enabled: true
414
+ }
415
+ },
416
+ // ============================================================================
417
+ // NEAR (1 network) - Uses NEP-366 meta-transactions
418
+ // ============================================================================
419
+ near: {
420
+ chainId: 0,
421
+ // Non-EVM
422
+ chainIdHex: "0x0",
423
+ name: "near",
424
+ displayName: "NEAR Protocol",
425
+ networkType: "near",
426
+ rpcUrl: "https://rpc.mainnet.near.org",
427
+ explorerUrl: "https://nearblocks.io",
428
+ nativeCurrency: {
429
+ name: "NEAR",
430
+ symbol: "NEAR",
431
+ decimals: 24
432
+ // NEAR uses 24 decimals (yoctoNEAR)
433
+ },
434
+ usdc: {
435
+ address: "17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1",
436
+ // Native Circle USDC
437
+ decimals: 6,
438
+ name: "USDC",
439
+ version: "1"
440
+ },
441
+ x402: {
442
+ facilitatorUrl: DEFAULT_FACILITATOR_URL,
443
+ enabled: true
444
+ // NEP-366 meta-transactions supported
445
+ }
446
+ }
447
+ };
448
+ var DEFAULT_CHAIN = "base";
449
+ function getChainById(chainId) {
450
+ return Object.values(SUPPORTED_CHAINS).find((chain) => chain.chainId === chainId);
451
+ }
452
+ function getChainByName(name) {
453
+ return SUPPORTED_CHAINS[name.toLowerCase()];
454
+ }
455
+ function isChainSupported(chainIdOrName) {
456
+ if (typeof chainIdOrName === "number") {
457
+ return Object.values(SUPPORTED_CHAINS).some((chain) => chain.chainId === chainIdOrName);
458
+ }
459
+ return chainIdOrName.toLowerCase() in SUPPORTED_CHAINS;
460
+ }
461
+ function getEnabledChains() {
462
+ return Object.values(SUPPORTED_CHAINS).filter((chain) => chain.x402.enabled);
463
+ }
464
+ function getChainsByNetworkType(networkType) {
465
+ return Object.values(SUPPORTED_CHAINS).filter(
466
+ (chain) => chain.networkType === networkType && chain.x402.enabled
467
+ );
468
+ }
469
+ function getEVMChainIds() {
470
+ return getChainsByNetworkType("evm").map((chain) => chain.chainId);
471
+ }
472
+ function getSVMChains() {
473
+ return Object.values(SUPPORTED_CHAINS).filter(
474
+ (chain) => chain.networkType === "svm" && chain.x402.enabled
475
+ );
476
+ }
477
+ function isSVMChain(chainName) {
478
+ const chain = getChainByName(chainName);
479
+ return chain?.networkType === "svm";
480
+ }
481
+ function getNetworkType(chainName) {
482
+ const chain = getChainByName(chainName);
483
+ return chain?.networkType;
484
+ }
485
+ function getExplorerTxUrl(chainName, txHash) {
486
+ const chain = getChainByName(chainName);
487
+ if (!chain) return null;
488
+ switch (chain.networkType) {
489
+ case "evm":
490
+ return `${chain.explorerUrl}/tx/${txHash}`;
491
+ case "svm":
492
+ case "solana":
493
+ return `${chain.explorerUrl}/tx/${txHash}`;
494
+ case "stellar":
495
+ return `${chain.explorerUrl}/tx/${txHash}`;
496
+ case "near":
497
+ return `${chain.explorerUrl}/txns/${txHash}`;
498
+ default:
499
+ return null;
500
+ }
501
+ }
502
+ function getExplorerAddressUrl(chainName, address) {
503
+ const chain = getChainByName(chainName);
504
+ if (!chain) return null;
505
+ switch (chain.networkType) {
506
+ case "evm":
507
+ return `${chain.explorerUrl}/address/${address}`;
508
+ case "svm":
509
+ case "solana":
510
+ return `${chain.explorerUrl}/account/${address}`;
511
+ case "stellar":
512
+ return `${chain.explorerUrl}/account/${address}`;
513
+ case "near":
514
+ return `${chain.explorerUrl}/address/${address}`;
515
+ default:
516
+ return null;
517
+ }
518
+ }
519
+
520
+ // src/client/X402Client.ts
521
+ var X402Client = class {
522
+ // Configuration
523
+ config;
524
+ // Wallet state
525
+ provider = null;
526
+ signer = null;
527
+ connectedAddress = null;
528
+ currentChainId = null;
529
+ currentNetwork = null;
530
+ currentChainName = null;
531
+ // Event emitter
532
+ eventHandlers = /* @__PURE__ */ new Map();
533
+ constructor(config = {}) {
534
+ this.config = {
535
+ ...DEFAULT_CONFIG,
536
+ ...config
537
+ };
538
+ if (config.rpcOverrides) {
539
+ for (const [chainName, rpcUrl] of Object.entries(config.rpcOverrides)) {
540
+ if (SUPPORTED_CHAINS[chainName]) {
541
+ SUPPORTED_CHAINS[chainName].rpcUrl = rpcUrl;
542
+ }
543
+ }
544
+ }
545
+ if (config.customChains) {
546
+ for (const [chainName, chainConfig] of Object.entries(config.customChains)) {
547
+ if (SUPPORTED_CHAINS[chainName]) {
548
+ Object.assign(SUPPORTED_CHAINS[chainName], chainConfig);
549
+ }
550
+ }
551
+ }
552
+ this.log("X402Client initialized", { config: this.config });
553
+ }
554
+ // ============================================================================
555
+ // PUBLIC API - Wallet Connection
556
+ // ============================================================================
557
+ /**
558
+ * Connect to a wallet on the specified chain
559
+ */
560
+ async connect(chainName) {
561
+ const targetChain = chainName || this.config.defaultChain;
562
+ const chain = getChainByName(targetChain);
563
+ if (!chain) {
564
+ throw new X402Error(`Unsupported chain: ${targetChain}`, "CHAIN_NOT_SUPPORTED");
565
+ }
566
+ if (!chain.x402.enabled) {
567
+ throw new X402Error(`Chain ${targetChain} is not enabled for x402 payments`, "CHAIN_NOT_SUPPORTED");
568
+ }
569
+ this.log(`Connecting wallet on ${chain.displayName}...`);
570
+ switch (chain.networkType) {
571
+ case "evm":
572
+ return this.connectEVMWallet(chain);
573
+ case "solana":
574
+ throw new X402Error(
575
+ 'Solana support requires importing from "uvd-x402-sdk/solana"',
576
+ "CHAIN_NOT_SUPPORTED"
577
+ );
578
+ case "stellar":
579
+ throw new X402Error(
580
+ 'Stellar support requires importing from "uvd-x402-sdk/stellar"',
581
+ "CHAIN_NOT_SUPPORTED"
582
+ );
583
+ case "near":
584
+ throw new X402Error("NEAR is not yet supported by the facilitator", "CHAIN_NOT_SUPPORTED");
585
+ default:
586
+ throw new X402Error(`Unknown network type for chain ${targetChain}`, "CHAIN_NOT_SUPPORTED");
587
+ }
588
+ }
589
+ /**
590
+ * Disconnect the current wallet
591
+ */
592
+ async disconnect() {
593
+ this.provider = null;
594
+ this.signer = null;
595
+ this.connectedAddress = null;
596
+ this.currentChainId = null;
597
+ this.currentNetwork = null;
598
+ this.currentChainName = null;
599
+ this.emit("disconnect", void 0);
600
+ this.log("Wallet disconnected");
601
+ }
602
+ /**
603
+ * Switch to a different chain (EVM only)
604
+ */
605
+ async switchChain(chainName) {
606
+ const chain = getChainByName(chainName);
607
+ if (!chain) {
608
+ throw new X402Error(`Unsupported chain: ${chainName}`, "CHAIN_NOT_SUPPORTED");
609
+ }
610
+ if (chain.networkType !== "evm") {
611
+ throw new X402Error(
612
+ "switchChain is only supported for EVM networks. Reconnect with connect() for other networks.",
613
+ "CHAIN_NOT_SUPPORTED"
614
+ );
615
+ }
616
+ if (!this.provider) {
617
+ throw new X402Error("Wallet not connected", "WALLET_NOT_CONNECTED");
618
+ }
619
+ await this.switchEVMChain(chain);
620
+ }
621
+ // ============================================================================
622
+ // PUBLIC API - Payment Creation
623
+ // ============================================================================
624
+ /**
625
+ * Create a payment authorization
626
+ *
627
+ * @param paymentInfo - Payment information from 402 response
628
+ * @returns Payment result with encoded X-PAYMENT header
629
+ */
630
+ async createPayment(paymentInfo) {
631
+ if (!this.connectedAddress) {
632
+ throw new X402Error("Wallet not connected", "WALLET_NOT_CONNECTED");
633
+ }
634
+ if (!this.currentChainName) {
635
+ throw new X402Error("Chain not set", "CHAIN_NOT_SUPPORTED");
636
+ }
637
+ const chain = getChainByName(this.currentChainName);
638
+ if (!chain) {
639
+ throw new X402Error(`Chain ${this.currentChainName} not found`, "CHAIN_NOT_SUPPORTED");
640
+ }
641
+ this.emit("paymentStarted", { amount: paymentInfo.amount, network: chain.name });
642
+ this.log("Creating payment...", { paymentInfo, chain: chain.name });
643
+ try {
644
+ switch (chain.networkType) {
645
+ case "evm":
646
+ return await this.createEVMPayment(paymentInfo, chain);
647
+ default:
648
+ throw new X402Error(
649
+ `Payment creation for ${chain.networkType} requires the appropriate provider`,
650
+ "CHAIN_NOT_SUPPORTED"
651
+ );
652
+ }
653
+ } catch (error) {
654
+ const x402Error = error instanceof X402Error ? error : new X402Error(
655
+ error instanceof Error ? error.message : "Unknown error",
656
+ "PAYMENT_FAILED",
657
+ error
658
+ );
659
+ this.emit("paymentFailed", { error: x402Error.message, code: x402Error.code });
660
+ throw x402Error;
661
+ }
662
+ }
663
+ /**
664
+ * Check USDC balance on current chain
665
+ */
666
+ async getBalance() {
667
+ if (!this.connectedAddress || !this.currentChainName) {
668
+ throw new X402Error("Wallet not connected", "WALLET_NOT_CONNECTED");
669
+ }
670
+ const chain = getChainByName(this.currentChainName);
671
+ if (!chain) {
672
+ throw new X402Error(`Chain ${this.currentChainName} not found`, "CHAIN_NOT_SUPPORTED");
673
+ }
674
+ switch (chain.networkType) {
675
+ case "evm":
676
+ return this.getEVMBalance(chain);
677
+ default:
678
+ throw new X402Error(
679
+ `Balance check for ${chain.networkType} requires the appropriate provider`,
680
+ "CHAIN_NOT_SUPPORTED"
681
+ );
682
+ }
683
+ }
684
+ // ============================================================================
685
+ // PUBLIC API - Getters
686
+ // ============================================================================
687
+ /**
688
+ * Get current wallet state
689
+ */
690
+ getState() {
691
+ return {
692
+ connected: this.connectedAddress !== null,
693
+ address: this.connectedAddress,
694
+ chainId: this.currentChainId,
695
+ network: this.currentChainName,
696
+ networkType: this.currentNetwork,
697
+ balance: null
698
+ // Call getBalance() separately
699
+ };
700
+ }
701
+ /**
702
+ * Get connected wallet address
703
+ */
704
+ getAddress() {
705
+ return this.connectedAddress;
706
+ }
707
+ /**
708
+ * Get current chain ID
709
+ */
710
+ getChainId() {
711
+ return this.currentChainId;
712
+ }
713
+ /**
714
+ * Get current chain name
715
+ */
716
+ getChainName() {
717
+ return this.currentChainName;
718
+ }
719
+ /**
720
+ * Get current chain display name
721
+ */
722
+ getChainDisplayName() {
723
+ if (!this.currentChainName) return null;
724
+ const chain = getChainByName(this.currentChainName);
725
+ return chain?.displayName ?? null;
726
+ }
727
+ /**
728
+ * Check if wallet is connected
729
+ */
730
+ isConnected() {
731
+ return this.connectedAddress !== null;
732
+ }
733
+ /**
734
+ * Get list of enabled chains
735
+ */
736
+ getEnabledChains() {
737
+ return getEnabledChains();
738
+ }
739
+ /**
740
+ * Get chain config by name
741
+ */
742
+ getChain(name) {
743
+ return getChainByName(name);
744
+ }
745
+ // ============================================================================
746
+ // PUBLIC API - Events
747
+ // ============================================================================
748
+ /**
749
+ * Subscribe to an event
750
+ */
751
+ on(event, handler) {
752
+ if (!this.eventHandlers.has(event)) {
753
+ this.eventHandlers.set(event, /* @__PURE__ */ new Set());
754
+ }
755
+ this.eventHandlers.get(event).add(handler);
756
+ return () => this.off(event, handler);
757
+ }
758
+ /**
759
+ * Unsubscribe from an event
760
+ */
761
+ off(event, handler) {
762
+ this.eventHandlers.get(event)?.delete(handler);
763
+ }
764
+ // ============================================================================
765
+ // PRIVATE - EVM Wallet Connection
766
+ // ============================================================================
767
+ async connectEVMWallet(chain) {
768
+ if (typeof window === "undefined" || !window.ethereum) {
769
+ throw new X402Error(
770
+ "No Ethereum wallet found. Please install MetaMask or another EVM wallet.",
771
+ "WALLET_NOT_FOUND"
772
+ );
773
+ }
774
+ try {
775
+ this.provider = new ethers.ethers.BrowserProvider(window.ethereum);
776
+ await this.provider.send("eth_requestAccounts", []);
777
+ await this.switchEVMChain(chain);
778
+ this.signer = await this.provider.getSigner();
779
+ this.connectedAddress = await this.signer.getAddress();
780
+ this.currentChainId = chain.chainId;
781
+ this.currentNetwork = "evm";
782
+ this.currentChainName = chain.name;
783
+ this.setupEVMEventListeners();
784
+ const state = this.getState();
785
+ this.emit("connect", state);
786
+ this.log("EVM wallet connected", { address: this.connectedAddress, chain: chain.name });
787
+ return this.connectedAddress;
788
+ } catch (error) {
789
+ if (error instanceof Error) {
790
+ if (error.message.includes("User rejected") || error.code === 4001) {
791
+ throw new X402Error("Connection rejected by user", "WALLET_CONNECTION_REJECTED");
792
+ }
793
+ }
794
+ throw new X402Error(
795
+ `Failed to connect wallet: ${error instanceof Error ? error.message : "Unknown error"}`,
796
+ "UNKNOWN_ERROR",
797
+ error
798
+ );
799
+ }
800
+ }
801
+ async switchEVMChain(chain) {
802
+ if (!this.provider) {
803
+ throw new X402Error("Wallet not connected", "WALLET_NOT_CONNECTED");
804
+ }
805
+ try {
806
+ await this.provider.send("wallet_switchEthereumChain", [{ chainId: chain.chainIdHex }]);
807
+ } catch (switchError) {
808
+ if (switchError.code === 4902) {
809
+ try {
810
+ await this.provider.send("wallet_addEthereumChain", [
811
+ {
812
+ chainId: chain.chainIdHex,
813
+ chainName: chain.displayName,
814
+ nativeCurrency: chain.nativeCurrency,
815
+ rpcUrls: [chain.rpcUrl],
816
+ blockExplorerUrls: [chain.explorerUrl]
817
+ }
818
+ ]);
819
+ } catch (addError) {
820
+ throw new X402Error(
821
+ `Failed to add ${chain.displayName} network`,
822
+ "CHAIN_SWITCH_REJECTED",
823
+ addError
824
+ );
825
+ }
826
+ } else if (switchError.code === 4001) {
827
+ throw new X402Error("Network switch rejected by user", "CHAIN_SWITCH_REJECTED");
828
+ } else {
829
+ throw new X402Error(
830
+ `Failed to switch to ${chain.displayName}`,
831
+ "CHAIN_SWITCH_REJECTED",
832
+ switchError
833
+ );
834
+ }
835
+ }
836
+ this.currentChainId = chain.chainId;
837
+ this.currentChainName = chain.name;
838
+ this.emit("chainChanged", { chainId: chain.chainId, chainName: chain.name });
839
+ }
840
+ setupEVMEventListeners() {
841
+ if (typeof window === "undefined" || !window.ethereum) return;
842
+ window.ethereum.on?.("accountsChanged", ((...args) => {
843
+ const accounts = args[0];
844
+ if (accounts.length === 0) {
845
+ this.disconnect();
846
+ } else if (accounts[0] !== this.connectedAddress) {
847
+ this.connectedAddress = accounts[0];
848
+ this.emit("accountChanged", { address: accounts[0] });
849
+ }
850
+ }));
851
+ window.ethereum.on?.("chainChanged", ((...args) => {
852
+ const chainIdHex = args[0];
853
+ const chainId = parseInt(chainIdHex, 16);
854
+ const chain = getChainById(chainId);
855
+ if (chain) {
856
+ this.currentChainId = chainId;
857
+ this.currentChainName = chain.name;
858
+ this.emit("chainChanged", { chainId, chainName: chain.name });
859
+ }
860
+ }));
861
+ }
862
+ // ============================================================================
863
+ // PRIVATE - EVM Payment Creation
864
+ // ============================================================================
865
+ async createEVMPayment(paymentInfo, chain) {
866
+ if (!this.signer) {
867
+ throw new X402Error("Wallet not connected", "WALLET_NOT_CONNECTED");
868
+ }
869
+ const recipient = this.getRecipientForNetwork(paymentInfo, "evm");
870
+ const nonceBytes = new Uint8Array(32);
871
+ if (typeof window !== "undefined" && window.crypto) {
872
+ window.crypto.getRandomValues(nonceBytes);
873
+ } else {
874
+ for (let i = 0; i < 32; i++) {
875
+ nonceBytes[i] = Math.floor(Math.random() * 256);
876
+ }
877
+ }
878
+ const nonce = ethers.ethers.hexlify(nonceBytes);
879
+ const validAfter = 0;
880
+ const validityWindowSeconds = chain.name === "base" ? 300 : 60;
881
+ const validBefore = Math.floor(Date.now() / 1e3) + validityWindowSeconds;
882
+ const domain = {
883
+ name: chain.usdc.name,
884
+ version: chain.usdc.version,
885
+ chainId: chain.chainId,
886
+ verifyingContract: chain.usdc.address
887
+ };
888
+ const types = {
889
+ TransferWithAuthorization: [
890
+ { name: "from", type: "address" },
891
+ { name: "to", type: "address" },
892
+ { name: "value", type: "uint256" },
893
+ { name: "validAfter", type: "uint256" },
894
+ { name: "validBefore", type: "uint256" },
895
+ { name: "nonce", type: "bytes32" }
896
+ ]
897
+ };
898
+ const value = ethers.ethers.parseUnits(paymentInfo.amount, chain.usdc.decimals);
899
+ const from = await this.signer.getAddress();
900
+ const to = ethers.ethers.getAddress(recipient);
901
+ const message = {
902
+ from,
903
+ to,
904
+ value,
905
+ validAfter,
906
+ validBefore,
907
+ nonce
908
+ };
909
+ this.log("Signing EIP-712 message...", { domain, message });
910
+ let signature;
911
+ try {
912
+ signature = await this.signer.signTypedData(domain, types, message);
913
+ } catch (error) {
914
+ if (error instanceof Error && (error.message.includes("User rejected") || error.code === 4001)) {
915
+ throw new X402Error("Signature rejected by user", "SIGNATURE_REJECTED");
916
+ }
917
+ throw new X402Error(
918
+ `Failed to sign payment: ${error instanceof Error ? error.message : "Unknown error"}`,
919
+ "PAYMENT_FAILED",
920
+ error
921
+ );
922
+ }
923
+ const sig = ethers.ethers.Signature.from(signature);
924
+ const payload = {
925
+ from,
926
+ to,
927
+ value: value.toString(),
928
+ validAfter,
929
+ validBefore,
930
+ nonce,
931
+ v: sig.v,
932
+ r: sig.r,
933
+ s: sig.s,
934
+ chainId: chain.chainId,
935
+ token: chain.usdc.address
936
+ };
937
+ const paymentHeader = this.encodeEVMPaymentHeader(payload, chain);
938
+ this.emit("paymentSigned", { paymentHeader });
939
+ const result = {
940
+ success: true,
941
+ paymentHeader,
942
+ network: chain.name,
943
+ payer: from
944
+ };
945
+ this.emit("paymentCompleted", result);
946
+ this.log("Payment created successfully", { network: chain.name, from });
947
+ return result;
948
+ }
949
+ encodeEVMPaymentHeader(payload, chain) {
950
+ const fullSignature = payload.r + payload.s.slice(2) + payload.v.toString(16).padStart(2, "0");
951
+ const x402Payload = {
952
+ x402Version: 1,
953
+ scheme: "exact",
954
+ network: chain.name,
955
+ payload: {
956
+ signature: fullSignature,
957
+ authorization: {
958
+ from: payload.from,
959
+ to: payload.to,
960
+ value: payload.value,
961
+ validAfter: payload.validAfter.toString(),
962
+ validBefore: payload.validBefore.toString(),
963
+ nonce: payload.nonce
964
+ }
965
+ }
966
+ };
967
+ const jsonString = JSON.stringify(x402Payload);
968
+ return btoa(jsonString);
969
+ }
970
+ // ============================================================================
971
+ // PRIVATE - EVM Balance Check
972
+ // ============================================================================
973
+ async getEVMBalance(chain) {
974
+ const publicProvider = new ethers.ethers.JsonRpcProvider(chain.rpcUrl);
975
+ const usdcAbi = ["function balanceOf(address owner) view returns (uint256)"];
976
+ const usdcContract = new ethers.ethers.Contract(chain.usdc.address, usdcAbi, publicProvider);
977
+ try {
978
+ const balance = await usdcContract.balanceOf(this.connectedAddress);
979
+ const formatted = ethers.ethers.formatUnits(balance, chain.usdc.decimals);
980
+ return parseFloat(formatted).toFixed(2);
981
+ } catch {
982
+ return "0.00";
983
+ }
984
+ }
985
+ // ============================================================================
986
+ // PRIVATE - Utilities
987
+ // ============================================================================
988
+ getRecipientForNetwork(paymentInfo, network) {
989
+ const lookupNetwork = network === "svm" ? "solana" : network;
990
+ const recipients = paymentInfo.recipients;
991
+ if (recipients?.[lookupNetwork]) {
992
+ return recipients[lookupNetwork];
993
+ }
994
+ return paymentInfo.recipient;
995
+ }
996
+ emit(event, data) {
997
+ this.eventHandlers.get(event)?.forEach((handler) => {
998
+ try {
999
+ handler(data);
1000
+ } catch (error) {
1001
+ console.error(`Error in ${event} handler:`, error);
1002
+ }
1003
+ });
1004
+ }
1005
+ log(message, data) {
1006
+ if (this.config.debug) {
1007
+ console.log(`[X402Client] ${message}`, data ?? "");
1008
+ }
1009
+ }
1010
+ };
1011
+
1012
+ // src/utils/x402.ts
1013
+ function detectX402Version(data) {
1014
+ if (typeof data !== "object" || data === null) {
1015
+ return 1;
1016
+ }
1017
+ const obj = data;
1018
+ if (obj.x402Version === 2) {
1019
+ return 2;
1020
+ }
1021
+ if (obj.accepts && Array.isArray(obj.accepts)) {
1022
+ return 2;
1023
+ }
1024
+ if (typeof obj.network === "string") {
1025
+ if (obj.network.includes(":")) {
1026
+ return 2;
1027
+ }
1028
+ }
1029
+ return 1;
1030
+ }
1031
+ function chainToCAIP2(chainName) {
1032
+ const caip2 = CAIP2_IDENTIFIERS[chainName.toLowerCase()];
1033
+ if (caip2) {
1034
+ return caip2;
1035
+ }
1036
+ const chain = getChainByName(chainName);
1037
+ if (chain) {
1038
+ if (chain.networkType === "evm") {
1039
+ return `eip155:${chain.chainId}`;
1040
+ }
1041
+ return `${chain.networkType}:${chainName}`;
1042
+ }
1043
+ return chainName;
1044
+ }
1045
+ function caip2ToChain(caip2) {
1046
+ if (CAIP2_TO_CHAIN[caip2]) {
1047
+ return CAIP2_TO_CHAIN[caip2];
1048
+ }
1049
+ const match = caip2.match(/^eip155:(\d+)$/);
1050
+ if (match) {
1051
+ const chainId = parseInt(match[1], 10);
1052
+ for (const [name, _config] of Object.entries(CAIP2_IDENTIFIERS)) {
1053
+ const chain = getChainByName(name);
1054
+ if (chain?.chainId === chainId) {
1055
+ return name;
1056
+ }
1057
+ }
1058
+ }
1059
+ const parts = caip2.split(":");
1060
+ if (parts.length === 2) {
1061
+ const networkName = parts[1];
1062
+ if (getChainByName(networkName)) {
1063
+ return networkName;
1064
+ }
1065
+ }
1066
+ return null;
1067
+ }
1068
+ function parseNetworkIdentifier(network) {
1069
+ if (network.includes(":")) {
1070
+ return caip2ToChain(network) || network;
1071
+ }
1072
+ return network.toLowerCase();
1073
+ }
1074
+ function encodeX402Header(header) {
1075
+ return btoa(JSON.stringify(header));
1076
+ }
1077
+ function decodeX402Header(encoded) {
1078
+ const json = atob(encoded);
1079
+ return JSON.parse(json);
1080
+ }
1081
+ function createX402V1Header(network, payload) {
1082
+ return {
1083
+ x402Version: 1,
1084
+ scheme: "exact",
1085
+ network,
1086
+ payload
1087
+ };
1088
+ }
1089
+ function createX402V2Header(network, payload, accepts) {
1090
+ const header = {
1091
+ x402Version: 2,
1092
+ scheme: "exact",
1093
+ network: network.includes(":") ? network : chainToCAIP2(network),
1094
+ payload
1095
+ };
1096
+ if (accepts && accepts.length > 0) {
1097
+ header.accepts = accepts;
1098
+ }
1099
+ return header;
1100
+ }
1101
+ function createX402Header(chainConfig, payload, version = "auto") {
1102
+ const effectiveVersion = version === "auto" ? 1 : version;
1103
+ if (effectiveVersion === 2) {
1104
+ return createX402V2Header(chainConfig.name, payload);
1105
+ }
1106
+ return createX402V1Header(chainConfig.name, payload);
1107
+ }
1108
+ function generatePaymentOptions(chainConfigs, amount, facilitator) {
1109
+ return chainConfigs.filter((chain) => chain.x402.enabled).map((chain) => {
1110
+ const atomicAmount = Math.floor(
1111
+ parseFloat(amount) * Math.pow(10, chain.usdc.decimals)
1112
+ ).toString();
1113
+ return {
1114
+ network: chainToCAIP2(chain.name),
1115
+ asset: chain.usdc.address,
1116
+ amount: atomicAmount,
1117
+ facilitator: facilitator || chain.x402.facilitatorUrl
1118
+ };
1119
+ });
1120
+ }
1121
+ function isCAIP2Format(network) {
1122
+ return network.includes(":");
1123
+ }
1124
+ function convertX402Header(header, targetVersion) {
1125
+ if (header.x402Version === targetVersion) {
1126
+ return header;
1127
+ }
1128
+ if (targetVersion === 2) {
1129
+ return {
1130
+ x402Version: 2,
1131
+ scheme: "exact",
1132
+ network: chainToCAIP2(header.network),
1133
+ payload: header.payload
1134
+ };
1135
+ } else {
1136
+ const chainName = isCAIP2Format(header.network) ? caip2ToChain(header.network) || header.network : header.network;
1137
+ return {
1138
+ x402Version: 1,
1139
+ scheme: "exact",
1140
+ network: chainName,
1141
+ payload: header.payload
1142
+ };
1143
+ }
1144
+ }
1145
+
1146
+ exports.CAIP2_IDENTIFIERS = CAIP2_IDENTIFIERS;
1147
+ exports.CAIP2_TO_CHAIN = CAIP2_TO_CHAIN;
1148
+ exports.DEFAULT_CHAIN = DEFAULT_CHAIN;
1149
+ exports.DEFAULT_CONFIG = DEFAULT_CONFIG;
1150
+ exports.DEFAULT_FACILITATOR_URL = DEFAULT_FACILITATOR_URL;
1151
+ exports.SUPPORTED_CHAINS = SUPPORTED_CHAINS;
1152
+ exports.X402Client = X402Client;
1153
+ exports.X402Error = X402Error;
1154
+ exports.caip2ToChain = caip2ToChain;
1155
+ exports.chainToCAIP2 = chainToCAIP2;
1156
+ exports.convertX402Header = convertX402Header;
1157
+ exports.createX402Header = createX402Header;
1158
+ exports.createX402V1Header = createX402V1Header;
1159
+ exports.createX402V2Header = createX402V2Header;
1160
+ exports.decodeX402Header = decodeX402Header;
1161
+ exports.detectX402Version = detectX402Version;
1162
+ exports.encodeX402Header = encodeX402Header;
1163
+ exports.generatePaymentOptions = generatePaymentOptions;
1164
+ exports.getChainById = getChainById;
1165
+ exports.getChainByName = getChainByName;
1166
+ exports.getChainsByNetworkType = getChainsByNetworkType;
1167
+ exports.getEVMChainIds = getEVMChainIds;
1168
+ exports.getEnabledChains = getEnabledChains;
1169
+ exports.getExplorerAddressUrl = getExplorerAddressUrl;
1170
+ exports.getExplorerTxUrl = getExplorerTxUrl;
1171
+ exports.getNetworkType = getNetworkType;
1172
+ exports.getSVMChains = getSVMChains;
1173
+ exports.isCAIP2Format = isCAIP2Format;
1174
+ exports.isChainSupported = isChainSupported;
1175
+ exports.isSVMChain = isSVMChain;
1176
+ exports.parseNetworkIdentifier = parseNetworkIdentifier;
1177
+ //# sourceMappingURL=index.js.map
1178
+ //# sourceMappingURL=index.js.map