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