uvd-x402-sdk 2.0.3 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/README.md +282 -15
  2. package/dist/adapters/index.d.mts +139 -0
  3. package/dist/adapters/index.d.ts +139 -0
  4. package/dist/adapters/index.js +724 -0
  5. package/dist/adapters/index.js.map +1 -0
  6. package/dist/adapters/index.mjs +720 -0
  7. package/dist/adapters/index.mjs.map +1 -0
  8. package/dist/{index-MTBgC_SL.d.mts → index-BHwtdJrt.d.mts} +45 -4
  9. package/dist/{index-MTBgC_SL.d.ts → index-BHwtdJrt.d.ts} +45 -4
  10. package/dist/{index-Db8dWNam.d.ts → index-CkDdnSNx.d.mts} +33 -2
  11. package/dist/{index-D0N_SYpK.d.mts → index-UTj85ZDJ.d.ts} +33 -2
  12. package/dist/index.d.mts +2 -2
  13. package/dist/index.d.ts +2 -2
  14. package/dist/index.js +210 -0
  15. package/dist/index.js.map +1 -1
  16. package/dist/index.mjs +207 -1
  17. package/dist/index.mjs.map +1 -1
  18. package/dist/providers/evm/index.d.mts +19 -3
  19. package/dist/providers/evm/index.d.ts +19 -3
  20. package/dist/providers/evm/index.js +228 -12
  21. package/dist/providers/evm/index.js.map +1 -1
  22. package/dist/providers/evm/index.mjs +228 -12
  23. package/dist/providers/evm/index.mjs.map +1 -1
  24. package/dist/providers/near/index.d.mts +1 -1
  25. package/dist/providers/near/index.d.ts +1 -1
  26. package/dist/providers/near/index.js.map +1 -1
  27. package/dist/providers/near/index.mjs.map +1 -1
  28. package/dist/providers/solana/index.d.mts +1 -1
  29. package/dist/providers/solana/index.d.ts +1 -1
  30. package/dist/providers/solana/index.js +168 -0
  31. package/dist/providers/solana/index.js.map +1 -1
  32. package/dist/providers/solana/index.mjs +168 -0
  33. package/dist/providers/solana/index.mjs.map +1 -1
  34. package/dist/providers/stellar/index.d.mts +1 -1
  35. package/dist/providers/stellar/index.d.ts +1 -1
  36. package/dist/providers/stellar/index.js.map +1 -1
  37. package/dist/providers/stellar/index.mjs.map +1 -1
  38. package/dist/react/index.d.mts +3 -3
  39. package/dist/react/index.d.ts +3 -3
  40. package/dist/react/index.js +168 -0
  41. package/dist/react/index.js.map +1 -1
  42. package/dist/react/index.mjs +168 -0
  43. package/dist/react/index.mjs.map +1 -1
  44. package/dist/utils/index.d.mts +1 -1
  45. package/dist/utils/index.d.ts +1 -1
  46. package/dist/utils/index.js +168 -0
  47. package/dist/utils/index.js.map +1 -1
  48. package/dist/utils/index.mjs +168 -0
  49. package/dist/utils/index.mjs.map +1 -1
  50. package/package.json +10 -2
  51. package/src/adapters/index.ts +13 -0
  52. package/src/adapters/wagmi.ts +294 -0
  53. package/src/chains/index.ts +255 -1
  54. package/src/index.ts +9 -0
  55. package/src/providers/evm/index.ts +64 -16
  56. package/src/types/index.ts +46 -3
@@ -0,0 +1,294 @@
1
+ /**
2
+ * uvd-x402-sdk - Wagmi/Viem Adapter
3
+ *
4
+ * Provides integration with wagmi/viem for projects using RainbowKit,
5
+ * ConnectKit, or other wagmi-based wallet connection libraries.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * import { useWalletClient } from 'wagmi';
10
+ * import { createPaymentFromWalletClient } from 'uvd-x402-sdk/wagmi';
11
+ *
12
+ * function PayButton() {
13
+ * const { data: walletClient } = useWalletClient();
14
+ *
15
+ * const handlePay = async () => {
16
+ * const paymentHeader = await createPaymentFromWalletClient(walletClient, {
17
+ * recipient: '0x...',
18
+ * amount: '1.00',
19
+ * chainName: 'base',
20
+ * });
21
+ *
22
+ * // Use in your API request
23
+ * await fetch('/api/paid-endpoint', {
24
+ * headers: { 'X-PAYMENT': paymentHeader }
25
+ * });
26
+ * };
27
+ *
28
+ * return <button onClick={handlePay}>Pay $1.00</button>;
29
+ * }
30
+ * ```
31
+ */
32
+
33
+ import { getChainByName } from '../chains';
34
+ import { createX402V1Header, encodeX402Header } from '../utils';
35
+ import { X402Error } from '../types';
36
+ import type { PaymentResult } from '../types';
37
+
38
+ /**
39
+ * Viem WalletClient interface (minimal type to avoid viem dependency)
40
+ */
41
+ export interface WalletClient {
42
+ account: {
43
+ address: `0x${string}`;
44
+ };
45
+ signTypedData: (args: {
46
+ domain: {
47
+ name: string;
48
+ version: string;
49
+ chainId: number;
50
+ verifyingContract: `0x${string}`;
51
+ };
52
+ types: Record<string, Array<{ name: string; type: string }>>;
53
+ primaryType: string;
54
+ message: Record<string, unknown>;
55
+ }) => Promise<`0x${string}`>;
56
+ }
57
+
58
+ /**
59
+ * Payment options for wagmi adapter
60
+ */
61
+ export interface WagmiPaymentOptions {
62
+ /** Recipient address */
63
+ recipient: string;
64
+ /** Amount in USDC (e.g., "1.00", "10.50") */
65
+ amount: string;
66
+ /** Chain name (default: 'base') */
67
+ chainName?: string;
68
+ /** Validity window in seconds (default: 300 = 5 minutes) */
69
+ validitySeconds?: number;
70
+ }
71
+
72
+ /**
73
+ * Generate a random 32-byte nonce as hex string
74
+ */
75
+ function generateNonce(): `0x${string}` {
76
+ const bytes = new Uint8Array(32);
77
+ if (typeof globalThis !== 'undefined' && globalThis.crypto?.getRandomValues) {
78
+ globalThis.crypto.getRandomValues(bytes);
79
+ } else if (typeof window !== 'undefined' && window.crypto?.getRandomValues) {
80
+ window.crypto.getRandomValues(bytes);
81
+ } else {
82
+ // Fallback for non-browser environments
83
+ for (let i = 0; i < 32; i++) {
84
+ bytes[i] = Math.floor(Math.random() * 256);
85
+ }
86
+ }
87
+ return ('0x' + Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('')) as `0x${string}`;
88
+ }
89
+
90
+ /**
91
+ * Parse amount string to atomic units (BigInt)
92
+ */
93
+ function parseUnits(amount: string, decimals: number): bigint {
94
+ const [integer, fraction = ''] = amount.split('.');
95
+ const paddedFraction = fraction.padEnd(decimals, '0').slice(0, decimals);
96
+ return BigInt(integer + paddedFraction);
97
+ }
98
+
99
+ /**
100
+ * Create an x402 payment header using a wagmi/viem WalletClient
101
+ *
102
+ * This function allows you to use the x402 SDK with wagmi-based wallet
103
+ * connections (RainbowKit, ConnectKit, etc.) instead of the built-in
104
+ * wallet connection.
105
+ *
106
+ * @param walletClient - The WalletClient from wagmi's useWalletClient hook
107
+ * @param options - Payment options (recipient, amount, chainName)
108
+ * @returns Base64-encoded payment header ready for X-PAYMENT HTTP header
109
+ *
110
+ * @example
111
+ * ```tsx
112
+ * import { useWalletClient } from 'wagmi';
113
+ * import { createPaymentFromWalletClient } from 'uvd-x402-sdk/wagmi';
114
+ *
115
+ * const { data: walletClient } = useWalletClient();
116
+ *
117
+ * const paymentHeader = await createPaymentFromWalletClient(walletClient, {
118
+ * recipient: '0xRecipientAddress',
119
+ * amount: '5.00',
120
+ * chainName: 'base',
121
+ * });
122
+ * ```
123
+ */
124
+ export async function createPaymentFromWalletClient(
125
+ walletClient: WalletClient | undefined | null,
126
+ options: WagmiPaymentOptions
127
+ ): Promise<string> {
128
+ if (!walletClient) {
129
+ throw new X402Error('WalletClient is not available. Make sure wallet is connected.', 'WALLET_NOT_CONNECTED');
130
+ }
131
+
132
+ const {
133
+ recipient,
134
+ amount,
135
+ chainName = 'base',
136
+ validitySeconds = 300,
137
+ } = options;
138
+
139
+ // Get chain configuration
140
+ const chain = getChainByName(chainName);
141
+ if (!chain) {
142
+ throw new X402Error(`Unsupported chain: ${chainName}`, 'CHAIN_NOT_SUPPORTED');
143
+ }
144
+
145
+ if (chain.networkType !== 'evm') {
146
+ throw new X402Error(
147
+ `wagmi adapter only supports EVM chains. For ${chain.networkType}, use the appropriate provider.`,
148
+ 'CHAIN_NOT_SUPPORTED'
149
+ );
150
+ }
151
+
152
+ const from = walletClient.account.address;
153
+ const to = recipient as `0x${string}`;
154
+ const nonce = generateNonce();
155
+ const validAfter = 0;
156
+ const validBefore = Math.floor(Date.now() / 1000) + validitySeconds;
157
+ const value = parseUnits(amount, chain.usdc.decimals);
158
+
159
+ // EIP-712 domain
160
+ const domain = {
161
+ name: chain.usdc.name,
162
+ version: chain.usdc.version,
163
+ chainId: chain.chainId,
164
+ verifyingContract: chain.usdc.address as `0x${string}`,
165
+ };
166
+
167
+ // EIP-712 types for TransferWithAuthorization (ERC-3009)
168
+ const types = {
169
+ TransferWithAuthorization: [
170
+ { name: 'from', type: 'address' },
171
+ { name: 'to', type: 'address' },
172
+ { name: 'value', type: 'uint256' },
173
+ { name: 'validAfter', type: 'uint256' },
174
+ { name: 'validBefore', type: 'uint256' },
175
+ { name: 'nonce', type: 'bytes32' },
176
+ ],
177
+ };
178
+
179
+ // Message to sign
180
+ const message = {
181
+ from,
182
+ to,
183
+ value,
184
+ validAfter: BigInt(validAfter),
185
+ validBefore: BigInt(validBefore),
186
+ nonce,
187
+ };
188
+
189
+ // Sign with viem
190
+ let signature: `0x${string}`;
191
+ try {
192
+ signature = await walletClient.signTypedData({
193
+ domain,
194
+ types,
195
+ primaryType: 'TransferWithAuthorization',
196
+ message,
197
+ });
198
+ } catch (error: unknown) {
199
+ if (error instanceof Error) {
200
+ if (error.message.includes('User rejected') || error.message.includes('denied')) {
201
+ throw new X402Error('Signature rejected by user', 'SIGNATURE_REJECTED');
202
+ }
203
+ }
204
+ throw new X402Error(
205
+ `Failed to sign payment: ${error instanceof Error ? error.message : 'Unknown error'}`,
206
+ 'PAYMENT_FAILED',
207
+ error
208
+ );
209
+ }
210
+
211
+ // Create x402 header with correct format
212
+ // IMPORTANT: validAfter, validBefore, and value must be STRINGS
213
+ const header = createX402V1Header(chainName, {
214
+ signature,
215
+ authorization: {
216
+ from,
217
+ to: recipient,
218
+ value: value.toString(),
219
+ validAfter: validAfter.toString(),
220
+ validBefore: validBefore.toString(),
221
+ nonce,
222
+ },
223
+ });
224
+
225
+ return encodeX402Header(header);
226
+ }
227
+
228
+ /**
229
+ * Create payment with full result object (includes metadata)
230
+ *
231
+ * Same as createPaymentFromWalletClient but returns a PaymentResult
232
+ * object with additional metadata.
233
+ *
234
+ * @param walletClient - The WalletClient from wagmi
235
+ * @param options - Payment options
236
+ * @returns PaymentResult with paymentHeader and metadata
237
+ */
238
+ export async function createPaymentWithResult(
239
+ walletClient: WalletClient | undefined | null,
240
+ options: WagmiPaymentOptions
241
+ ): Promise<PaymentResult> {
242
+ const paymentHeader = await createPaymentFromWalletClient(walletClient, options);
243
+
244
+ return {
245
+ success: true,
246
+ paymentHeader,
247
+ network: options.chainName || 'base',
248
+ payer: walletClient?.account.address,
249
+ };
250
+ }
251
+
252
+ /**
253
+ * React hook helper for wagmi integration
254
+ *
255
+ * Returns a function that creates payments using the connected wallet.
256
+ * This is a simple wrapper - for more control, use createPaymentFromWalletClient directly.
257
+ *
258
+ * @example
259
+ * ```tsx
260
+ * import { useWalletClient } from 'wagmi';
261
+ * import { useX402Wagmi } from 'uvd-x402-sdk/wagmi';
262
+ *
263
+ * function PayButton() {
264
+ * const { data: walletClient } = useWalletClient();
265
+ * const { createPayment, isReady } = useX402Wagmi(walletClient);
266
+ *
267
+ * return (
268
+ * <button
269
+ * disabled={!isReady}
270
+ * onClick={() => createPayment({ recipient: '0x...', amount: '1.00' })}
271
+ * >
272
+ * Pay
273
+ * </button>
274
+ * );
275
+ * }
276
+ * ```
277
+ */
278
+ export function useX402Wagmi(walletClient: WalletClient | undefined | null) {
279
+ const isReady = !!walletClient;
280
+
281
+ const createPayment = async (options: WagmiPaymentOptions): Promise<string> => {
282
+ return createPaymentFromWalletClient(walletClient, options);
283
+ };
284
+
285
+ const createPaymentFull = async (options: WagmiPaymentOptions): Promise<PaymentResult> => {
286
+ return createPaymentWithResult(walletClient, options);
287
+ };
288
+
289
+ return {
290
+ isReady,
291
+ createPayment,
292
+ createPaymentFull,
293
+ };
294
+ }
@@ -8,7 +8,7 @@
8
8
  * NEAR (1): Uses NEP-366 meta-transactions
9
9
  */
10
10
 
11
- import type { ChainConfig, NetworkType } from '../types';
11
+ import type { ChainConfig, NetworkType, TokenType, TokenConfig } from '../types';
12
12
 
13
13
  /**
14
14
  * Default facilitator URL for x402 payments
@@ -47,6 +47,26 @@ export const SUPPORTED_CHAINS: Record<string, ChainConfig> = {
47
47
  name: 'USD Coin',
48
48
  version: '2',
49
49
  },
50
+ tokens: {
51
+ usdc: {
52
+ address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
53
+ decimals: 6,
54
+ name: 'USD Coin',
55
+ version: '2',
56
+ },
57
+ eurc: {
58
+ address: '0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42',
59
+ decimals: 6,
60
+ name: 'EURC',
61
+ version: '2',
62
+ },
63
+ gho: {
64
+ address: '0x6Bb7a212910682DCFdbd5BCBb3e28FB4E8da10Ee',
65
+ decimals: 18,
66
+ name: 'Gho Token',
67
+ version: '1',
68
+ },
69
+ },
50
70
  x402: {
51
71
  facilitatorUrl: DEFAULT_FACILITATOR_URL,
52
72
  enabled: true,
@@ -72,6 +92,26 @@ export const SUPPORTED_CHAINS: Record<string, ChainConfig> = {
72
92
  name: 'USD Coin',
73
93
  version: '2',
74
94
  },
95
+ tokens: {
96
+ usdc: {
97
+ address: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',
98
+ decimals: 6,
99
+ name: 'USD Coin',
100
+ version: '2',
101
+ },
102
+ eurc: {
103
+ address: '0xC891EB4cbdEFf6e073e859e987815Ed1505c2ACD',
104
+ decimals: 6,
105
+ name: 'EURC',
106
+ version: '2',
107
+ },
108
+ ausd: {
109
+ address: '0x00000000eFE302BEAA2b3e6e1b18d08D69a9012a',
110
+ decimals: 6,
111
+ name: 'Agora USD',
112
+ version: '1',
113
+ },
114
+ },
75
115
  x402: {
76
116
  facilitatorUrl: DEFAULT_FACILITATOR_URL,
77
117
  enabled: true,
@@ -97,6 +137,44 @@ export const SUPPORTED_CHAINS: Record<string, ChainConfig> = {
97
137
  name: 'USD Coin',
98
138
  version: '2',
99
139
  },
140
+ tokens: {
141
+ usdc: {
142
+ address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
143
+ decimals: 6,
144
+ name: 'USD Coin',
145
+ version: '2',
146
+ },
147
+ eurc: {
148
+ address: '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c',
149
+ decimals: 6,
150
+ name: 'EURC',
151
+ version: '2',
152
+ },
153
+ ausd: {
154
+ address: '0x00000000eFE302BEAA2b3e6e1b18d08D69a9012a',
155
+ decimals: 6,
156
+ name: 'Agora USD',
157
+ version: '1',
158
+ },
159
+ pyusd: {
160
+ address: '0x6c3ea9036406852006290770BEdFcAbA0e23A0e8',
161
+ decimals: 6,
162
+ name: 'PayPal USD',
163
+ version: '1',
164
+ },
165
+ gho: {
166
+ address: '0x40D16FC0246aD3160Ccc09B8D0D3A2cD28aE6C2f',
167
+ decimals: 18,
168
+ name: 'Gho Token',
169
+ version: '1',
170
+ },
171
+ crvusd: {
172
+ address: '0xf939E0A03FB07F59A73314E73794Be0E57ac1b4E',
173
+ decimals: 18,
174
+ name: 'Curve.Fi USD Stablecoin',
175
+ version: '1',
176
+ },
177
+ },
100
178
  x402: {
101
179
  facilitatorUrl: DEFAULT_FACILITATOR_URL,
102
180
  enabled: true,
@@ -122,6 +200,20 @@ export const SUPPORTED_CHAINS: Record<string, ChainConfig> = {
122
200
  name: 'USD Coin',
123
201
  version: '2',
124
202
  },
203
+ tokens: {
204
+ usdc: {
205
+ address: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',
206
+ decimals: 6,
207
+ name: 'USD Coin',
208
+ version: '2',
209
+ },
210
+ ausd: {
211
+ address: '0x00000000eFE302BEAA2b3e6e1b18d08D69a9012a',
212
+ decimals: 6,
213
+ name: 'Agora USD',
214
+ version: '1',
215
+ },
216
+ },
125
217
  x402: {
126
218
  facilitatorUrl: DEFAULT_FACILITATOR_URL,
127
219
  enabled: true,
@@ -147,6 +239,32 @@ export const SUPPORTED_CHAINS: Record<string, ChainConfig> = {
147
239
  name: 'USD Coin',
148
240
  version: '2',
149
241
  },
242
+ tokens: {
243
+ usdc: {
244
+ address: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',
245
+ decimals: 6,
246
+ name: 'USD Coin',
247
+ version: '2',
248
+ },
249
+ ausd: {
250
+ address: '0x00000000eFE302BEAA2b3e6e1b18d08D69a9012a',
251
+ decimals: 6,
252
+ name: 'Agora USD',
253
+ version: '1',
254
+ },
255
+ gho: {
256
+ address: '0x7dfF72693f6A4149b17e7C6314655f6A9F7c8B33',
257
+ decimals: 18,
258
+ name: 'Gho Token',
259
+ version: '1',
260
+ },
261
+ crvusd: {
262
+ address: '0x498Bf2B1e120FeD3ad3D42EA2165E9b73f99C1e5',
263
+ decimals: 18,
264
+ name: 'Curve.Fi USD Stablecoin',
265
+ version: '1',
266
+ },
267
+ },
150
268
  x402: {
151
269
  facilitatorUrl: DEFAULT_FACILITATOR_URL,
152
270
  enabled: true,
@@ -172,6 +290,14 @@ export const SUPPORTED_CHAINS: Record<string, ChainConfig> = {
172
290
  name: 'USD Coin',
173
291
  version: '2',
174
292
  },
293
+ tokens: {
294
+ usdc: {
295
+ address: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85',
296
+ decimals: 6,
297
+ name: 'USD Coin',
298
+ version: '2',
299
+ },
300
+ },
175
301
  x402: {
176
302
  facilitatorUrl: DEFAULT_FACILITATOR_URL,
177
303
  enabled: true,
@@ -197,6 +323,14 @@ export const SUPPORTED_CHAINS: Record<string, ChainConfig> = {
197
323
  name: 'USDC', // Celo uses "USDC" not "USD Coin" for EIP-712
198
324
  version: '2',
199
325
  },
326
+ tokens: {
327
+ usdc: {
328
+ address: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C',
329
+ decimals: 6,
330
+ name: 'USDC', // Celo uses "USDC" not "USD Coin" for EIP-712
331
+ version: '2',
332
+ },
333
+ },
200
334
  x402: {
201
335
  facilitatorUrl: DEFAULT_FACILITATOR_URL,
202
336
  enabled: true,
@@ -222,6 +356,14 @@ export const SUPPORTED_CHAINS: Record<string, ChainConfig> = {
222
356
  name: 'USDC', // HyperEVM uses "USDC" not "USD Coin"
223
357
  version: '2',
224
358
  },
359
+ tokens: {
360
+ usdc: {
361
+ address: '0xb88339CB7199b77E23DB6E890353E22632Ba630f',
362
+ decimals: 6,
363
+ name: 'USDC', // HyperEVM uses "USDC" not "USD Coin"
364
+ version: '2',
365
+ },
366
+ },
225
367
  x402: {
226
368
  facilitatorUrl: DEFAULT_FACILITATOR_URL,
227
369
  enabled: true,
@@ -247,6 +389,14 @@ export const SUPPORTED_CHAINS: Record<string, ChainConfig> = {
247
389
  name: 'USDC', // Unichain uses "USDC" not "USD Coin"
248
390
  version: '2',
249
391
  },
392
+ tokens: {
393
+ usdc: {
394
+ address: '0x078d782b760474a361dda0af3839290b0ef57ad6',
395
+ decimals: 6,
396
+ name: 'USDC', // Unichain uses "USDC" not "USD Coin"
397
+ version: '2',
398
+ },
399
+ },
250
400
  x402: {
251
401
  facilitatorUrl: DEFAULT_FACILITATOR_URL,
252
402
  enabled: true,
@@ -272,6 +422,20 @@ export const SUPPORTED_CHAINS: Record<string, ChainConfig> = {
272
422
  name: 'USDC', // Monad uses "USDC" not "USD Coin"
273
423
  version: '2',
274
424
  },
425
+ tokens: {
426
+ usdc: {
427
+ address: '0x754704bc059f8c67012fed69bc8a327a5aafb603',
428
+ decimals: 6,
429
+ name: 'USDC', // Monad uses "USDC" not "USD Coin"
430
+ version: '2',
431
+ },
432
+ ausd: {
433
+ address: '0x00000000eFE302BEAA2b3e6e1b18d08D69a9012a',
434
+ decimals: 6,
435
+ name: 'Agora USD',
436
+ version: '1',
437
+ },
438
+ },
275
439
  x402: {
276
440
  facilitatorUrl: DEFAULT_FACILITATOR_URL,
277
441
  enabled: true,
@@ -511,3 +675,93 @@ export function getExplorerAddressUrl(chainName: string, address: string): strin
511
675
  return null;
512
676
  }
513
677
  }
678
+
679
+ // ============================================================================
680
+ // MULTI-TOKEN SUPPORT FUNCTIONS
681
+ // ============================================================================
682
+
683
+ /**
684
+ * Get token configuration for a specific chain and token type
685
+ * Falls back to USDC config if token not found (for backward compatibility)
686
+ *
687
+ * @param chainName - Chain name (e.g., 'ethereum', 'base')
688
+ * @param tokenType - Token type (e.g., 'usdc', 'eurc', 'gho')
689
+ * @returns Token configuration or undefined if chain not found
690
+ */
691
+ export function getTokenConfig(
692
+ chainName: string,
693
+ tokenType: TokenType = 'usdc'
694
+ ): TokenConfig | undefined {
695
+ const chain = getChainByName(chainName);
696
+ if (!chain) return undefined;
697
+
698
+ // Try to get from tokens map first (new multi-token support)
699
+ if (chain.tokens && chain.tokens[tokenType]) {
700
+ return chain.tokens[tokenType];
701
+ }
702
+
703
+ // Fall back to usdc config for backward compatibility
704
+ if (tokenType === 'usdc') {
705
+ return chain.usdc;
706
+ }
707
+
708
+ return undefined;
709
+ }
710
+
711
+ /**
712
+ * Get list of supported tokens for a chain
713
+ *
714
+ * @param chainName - Chain name (e.g., 'ethereum', 'base')
715
+ * @returns Array of supported token types, or empty array if chain not found
716
+ */
717
+ export function getSupportedTokens(chainName: string): TokenType[] {
718
+ const chain = getChainByName(chainName);
719
+ if (!chain) return [];
720
+
721
+ // If tokens map exists, return its keys
722
+ if (chain.tokens) {
723
+ return Object.keys(chain.tokens) as TokenType[];
724
+ }
725
+
726
+ // Default to just USDC for chains without explicit tokens map
727
+ return ['usdc'];
728
+ }
729
+
730
+ /**
731
+ * Check if a token is supported on a specific chain
732
+ *
733
+ * @param chainName - Chain name (e.g., 'ethereum', 'base')
734
+ * @param tokenType - Token type (e.g., 'usdc', 'eurc', 'gho')
735
+ * @returns true if token is supported on the chain
736
+ */
737
+ export function isTokenSupported(chainName: string, tokenType: TokenType): boolean {
738
+ const chain = getChainByName(chainName);
739
+ if (!chain) return false;
740
+
741
+ // Check tokens map
742
+ if (chain.tokens && chain.tokens[tokenType]) {
743
+ return true;
744
+ }
745
+
746
+ // USDC is always supported (backward compatibility)
747
+ if (tokenType === 'usdc') {
748
+ return true;
749
+ }
750
+
751
+ return false;
752
+ }
753
+
754
+ /**
755
+ * Get all chains that support a specific token
756
+ *
757
+ * @param tokenType - Token type (e.g., 'usdc', 'eurc', 'gho')
758
+ * @returns Array of chain configs that support the token
759
+ */
760
+ export function getChainsByToken(tokenType: TokenType): ChainConfig[] {
761
+ return Object.values(SUPPORTED_CHAINS).filter(chain => {
762
+ if (!chain.x402.enabled) return false;
763
+ if (chain.tokens && chain.tokens[tokenType]) return true;
764
+ if (tokenType === 'usdc') return true; // USDC is universal
765
+ return false;
766
+ });
767
+ }
package/src/index.ts CHANGED
@@ -95,6 +95,11 @@ export {
95
95
  getNetworkType,
96
96
  getExplorerTxUrl,
97
97
  getExplorerAddressUrl,
98
+ // Multi-token support functions
99
+ getTokenConfig,
100
+ getSupportedTokens,
101
+ isTokenSupported,
102
+ getChainsByToken,
98
103
  } from './chains';
99
104
 
100
105
  // x402 utilities
@@ -121,6 +126,10 @@ export type {
121
126
  NativeCurrency,
122
127
  NetworkType,
123
128
 
129
+ // Token types (multi-token support)
130
+ TokenType,
131
+ TokenConfig,
132
+
124
133
  // Wallet types
125
134
  WalletState,
126
135
  WalletAdapter,