uvd-x402-sdk 2.13.1 → 2.14.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 (56) hide show
  1. package/README.md +218 -1396
  2. package/dist/adapters/index.d.mts +1 -1
  3. package/dist/adapters/index.d.ts +1 -1
  4. package/dist/adapters/index.js.map +1 -1
  5. package/dist/adapters/index.mjs.map +1 -1
  6. package/dist/backend/index.d.mts +1 -1
  7. package/dist/backend/index.d.ts +1 -1
  8. package/dist/backend/index.js.map +1 -1
  9. package/dist/backend/index.mjs.map +1 -1
  10. package/dist/{index-fIhvHqCQ.d.mts → index-BYIugZlE.d.mts} +17 -0
  11. package/dist/{index-fIhvHqCQ.d.ts → index-BYIugZlE.d.ts} +17 -0
  12. package/dist/{index-DmJGKD9r.d.ts → index-Cwi_VM05.d.ts} +1 -1
  13. package/dist/{index-C6Vxnneo.d.mts → index-D3PO3jLW.d.mts} +1 -1
  14. package/dist/index.d.mts +42 -18
  15. package/dist/index.d.ts +42 -18
  16. package/dist/index.js +58 -16
  17. package/dist/index.js.map +1 -1
  18. package/dist/index.mjs +58 -16
  19. package/dist/index.mjs.map +1 -1
  20. package/dist/providers/algorand/index.d.mts +4 -1
  21. package/dist/providers/algorand/index.d.ts +4 -1
  22. package/dist/providers/algorand/index.js +83 -31
  23. package/dist/providers/algorand/index.js.map +1 -1
  24. package/dist/providers/algorand/index.mjs +83 -31
  25. package/dist/providers/algorand/index.mjs.map +1 -1
  26. package/dist/providers/evm/index.d.mts +1 -1
  27. package/dist/providers/evm/index.d.ts +1 -1
  28. package/dist/providers/evm/index.js.map +1 -1
  29. package/dist/providers/evm/index.mjs.map +1 -1
  30. package/dist/providers/near/index.d.mts +1 -1
  31. package/dist/providers/near/index.d.ts +1 -1
  32. package/dist/providers/near/index.js.map +1 -1
  33. package/dist/providers/near/index.mjs.map +1 -1
  34. package/dist/providers/solana/index.d.mts +1 -1
  35. package/dist/providers/solana/index.d.ts +1 -1
  36. package/dist/providers/solana/index.js +3 -0
  37. package/dist/providers/solana/index.js.map +1 -1
  38. package/dist/providers/solana/index.mjs +3 -0
  39. package/dist/providers/solana/index.mjs.map +1 -1
  40. package/dist/providers/stellar/index.d.mts +1 -1
  41. package/dist/providers/stellar/index.d.ts +1 -1
  42. package/dist/providers/stellar/index.js.map +1 -1
  43. package/dist/providers/stellar/index.mjs.map +1 -1
  44. package/dist/react/index.d.mts +3 -3
  45. package/dist/react/index.d.ts +3 -3
  46. package/dist/react/index.js.map +1 -1
  47. package/dist/react/index.mjs.map +1 -1
  48. package/dist/utils/index.d.mts +1 -1
  49. package/dist/utils/index.d.ts +1 -1
  50. package/dist/utils/index.js.map +1 -1
  51. package/dist/utils/index.mjs.map +1 -1
  52. package/package.json +1 -1
  53. package/src/facilitator.ts +64 -16
  54. package/src/providers/algorand/index.ts +33 -20
  55. package/src/providers/solana/index.ts +9 -2
  56. package/src/types/index.ts +18 -0
package/README.md CHANGED
@@ -1,51 +1,17 @@
1
1
  # uvd-x402-sdk
2
2
 
3
- > Gasless crypto payments across 14 blockchain networks using the x402 protocol.
3
+ Gasless crypto payments across 16 blockchain networks using the x402 protocol.
4
4
 
5
- The x402 SDK enables any application to accept stablecoin payments (USDC, EURC, AUSD, PYUSD, USDT) without requiring users to pay gas fees. Users sign a message or transaction, and the Ultravioleta facilitator handles on-chain settlement.
5
+ Users sign a message or transaction, and the Ultravioleta facilitator handles on-chain settlement. No gas fees for users.
6
6
 
7
7
  ## Features
8
8
 
9
- - **14 Supported Networks**: EVM chains, Solana, Fogo, Stellar, and NEAR
10
- - **Multi-Stablecoin**: USDC, EURC, AUSD, PYUSD, USDT support on EVM chains
11
- - **x402 v1 & v2**: Full support for both protocol versions with automatic detection
12
- - **Gasless Payments**: Users never pay gas - the facilitator covers all network fees
13
- - **Multi-Network**: Accept payments on multiple networks simultaneously
14
- - **Backend Utilities**: Server-side helpers for payment verification and settlement
15
- - **Bazaar Discovery**: Discover and register x402-enabled resources
16
- - **Escrow & Refunds**: Hold payments in escrow with refund and dispute support
17
- - **Type-Safe**: Comprehensive TypeScript definitions
18
- - **Framework Agnostic**: Works with any JavaScript framework
19
- - **React Hooks**: First-class React integration
20
- - **Wagmi/RainbowKit**: Dedicated adapter for wagmi-based apps
21
- - **Modular**: Import only what you need
22
-
23
- ## Quick Start
24
-
25
- ```typescript
26
- import { X402Client } from 'uvd-x402-sdk';
27
-
28
- const client = new X402Client({ defaultChain: 'base' });
29
-
30
- // Connect wallet
31
- const address = await client.connect('base');
32
-
33
- // Create payment
34
- const result = await client.createPayment({
35
- recipient: '0x...',
36
- amount: '10.00',
37
- });
38
-
39
- // Use in your API request
40
- await fetch('/api/purchase', {
41
- method: 'POST',
42
- headers: {
43
- 'Content-Type': 'application/json',
44
- 'X-PAYMENT': result.paymentHeader,
45
- },
46
- body: JSON.stringify({ item: 'premium-feature' }),
47
- });
48
- ```
9
+ - **16 Networks**: EVM (10), Solana, Fogo, Stellar, NEAR, Algorand (2)
10
+ - **Multi-Stablecoin**: USDC, EURC, AUSD, PYUSD, USDT
11
+ - **x402 v1 & v2**: Both protocol versions with auto-detection
12
+ - **Gasless**: Facilitator pays all network fees
13
+ - **Type-Safe**: Full TypeScript support
14
+ - **React & Wagmi**: First-class integrations
49
15
 
50
16
  ## Installation
51
17
 
@@ -53,13 +19,13 @@ await fetch('/api/purchase', {
53
19
  npm install uvd-x402-sdk
54
20
  ```
55
21
 
56
- ### Peer Dependencies by Network
22
+ ### Peer Dependencies
57
23
 
58
24
  ```bash
59
- # EVM chains (Base, Ethereum, etc.) - included by default
25
+ # EVM (included by default)
60
26
  npm install ethers@^6
61
27
 
62
- # Solana & Fogo (SVM chains)
28
+ # Solana/Fogo
63
29
  npm install @solana/web3.js @solana/spl-token
64
30
 
65
31
  # Stellar
@@ -68,112 +34,120 @@ npm install @stellar/stellar-sdk @stellar/freighter-api
68
34
  # NEAR
69
35
  npm install @near-wallet-selector/core @near-wallet-selector/my-near-wallet
70
36
 
71
- # React hooks (optional)
72
- npm install react
37
+ # Algorand
38
+ npm install algosdk lute-connect
73
39
  ```
74
40
 
75
- ---
76
-
77
- ## WalletConnect Integration
78
-
79
- The SDK works with any EVM wallet that injects into `window.ethereum`, including:
80
-
81
- - **Browser extensions**: MetaMask, Rainbow, Rabby, Coinbase Wallet
82
- - **Mobile wallets**: Rainbow, MetaMask Mobile, Trust Wallet (via WalletConnect)
83
-
84
- ### Using WalletConnect (Mobile Wallets)
41
+ ## Quick Start
85
42
 
86
- For mobile wallet support (Rainbow, MetaMask Mobile, etc.), initialize WalletConnect before using the SDK:
43
+ ### EVM Chains
87
44
 
88
45
  ```typescript
89
- import { EthereumProvider } from '@walletconnect/ethereum-provider';
90
46
  import { X402Client } from 'uvd-x402-sdk';
91
47
 
92
- // 1. Initialize WalletConnect
93
- const walletConnectProvider = await EthereumProvider.init({
94
- projectId: 'YOUR_WALLETCONNECT_PROJECT_ID', // Get from cloud.walletconnect.com
95
- chains: [8453], // Base mainnet
96
- optionalChains: [1, 137, 42161, 10], // ETH, Polygon, Arbitrum, Optimism
97
- showQrModal: true,
98
- });
99
-
100
- // 2. Connect wallet (shows QR code for mobile wallet to scan)
101
- await walletConnectProvider.connect();
102
-
103
- // 3. Use the SDK normally
104
48
  const client = new X402Client({ defaultChain: 'base' });
105
49
  const address = await client.connect('base');
106
50
 
107
- // 4. Create payment
108
51
  const result = await client.createPayment({
109
- recipient: '0xD3868E1eD738CED6945A574a7c769433BeD5d474',
52
+ recipient: '0x...',
110
53
  amount: '10.00',
111
54
  });
112
- ```
113
55
 
114
- ### Using Browser Extensions (Rainbow, MetaMask, etc.)
56
+ await fetch('/api/purchase', {
57
+ headers: { 'X-PAYMENT': result.paymentHeader },
58
+ });
59
+ ```
115
60
 
116
- Browser extension wallets work automatically - no extra setup needed:
61
+ ### Solana
117
62
 
118
63
  ```typescript
119
- import { X402Client } from 'uvd-x402-sdk';
120
-
121
- const client = new X402Client({ defaultChain: 'base' });
64
+ import { SVMProvider } from 'uvd-x402-sdk/solana';
65
+ import { getChainByName } from 'uvd-x402-sdk';
122
66
 
123
- // Connects to whatever wallet is installed (Rainbow, MetaMask, Rabby, etc.)
124
- const address = await client.connect('base');
67
+ const svm = new SVMProvider();
68
+ const address = await svm.connect();
69
+ const chainConfig = getChainByName('solana')!;
125
70
 
126
- const result = await client.createPayment({
127
- recipient: '0xD3868E1eD738CED6945A574a7c769433BeD5d474',
71
+ const payload = await svm.signPayment({
72
+ recipient: '5Y32Dk6weq1LrMRdujpJyDbTN3SjwXGoQS9QN39WQ9Cq',
128
73
  amount: '10.00',
129
- });
74
+ }, chainConfig);
75
+
76
+ const header = svm.encodePaymentHeader(payload, chainConfig);
130
77
  ```
131
78
 
132
- ---
79
+ ### Algorand
80
+
81
+ ```typescript
82
+ import { AlgorandProvider } from 'uvd-x402-sdk/algorand';
83
+ import { getChainByName } from 'uvd-x402-sdk';
84
+
85
+ const algorand = new AlgorandProvider();
86
+ const address = await algorand.connect(); // Lute or Pera wallet
87
+ const chainConfig = getChainByName('algorand')!;
88
+
89
+ const payload = await algorand.signPayment({
90
+ recipient: 'NCDSNUQ2QLXDMJXRALAW4CRUSSKG4IS37MVOFDQQPC45SE4EBZO42U6ZX4',
91
+ amount: '10.00',
92
+ }, chainConfig);
93
+
94
+ const header = algorand.encodePaymentHeader(payload, chainConfig);
95
+ ```
133
96
 
134
- ## Wagmi / RainbowKit Integration
97
+ Algorand uses atomic transaction groups:
98
+ - Transaction 0: Fee payment (unsigned, facilitator signs)
99
+ - Transaction 1: USDC ASA transfer (signed by user)
135
100
 
136
- If you're using wagmi with RainbowKit, ConnectKit, or other wagmi-based wallet libraries, use the dedicated wagmi adapter:
101
+ ### Stellar
137
102
 
138
103
  ```typescript
139
- import { useWalletClient } from 'wagmi';
140
- import { createPaymentFromWalletClient } from 'uvd-x402-sdk/wagmi';
104
+ import { StellarProvider } from 'uvd-x402-sdk/stellar';
105
+ import { getChainByName } from 'uvd-x402-sdk';
141
106
 
142
- function PayButton() {
143
- const { data: walletClient } = useWalletClient();
107
+ const stellar = new StellarProvider();
108
+ const address = await stellar.connect(); // Freighter wallet
109
+ const chainConfig = getChainByName('stellar')!;
144
110
 
145
- const handlePay = async () => {
146
- const paymentHeader = await createPaymentFromWalletClient(walletClient, {
147
- recipient: '0xD3868E1eD738CED6945A574a7c769433BeD5d474',
148
- amount: '10.00',
149
- chainName: 'base', // optional, defaults to 'base'
150
- });
111
+ const payload = await stellar.signPayment({
112
+ recipient: 'GD3FWQ4QFSCO2F2KVXZPQWOC27CQHXHYCRCRRZBMWU3DNOZW2IIGOU54',
113
+ amount: '10.00',
114
+ }, chainConfig);
151
115
 
152
- // Use in your API request
153
- await fetch('/api/purchase', {
154
- headers: { 'X-PAYMENT': paymentHeader },
155
- method: 'POST',
156
- });
157
- };
116
+ const header = stellar.encodePaymentHeader(payload);
117
+ ```
158
118
 
159
- return <button onClick={handlePay}>Pay $10 USDC</button>;
160
- }
119
+ ### NEAR
120
+
121
+ ```typescript
122
+ import { NEARProvider } from 'uvd-x402-sdk/near';
123
+ import { getChainByName } from 'uvd-x402-sdk';
124
+
125
+ const near = new NEARProvider();
126
+ const accountId = await near.connect(); // MyNearWallet
127
+ const chainConfig = getChainByName('near')!;
128
+
129
+ const payload = await near.signPayment({
130
+ recipient: 'merchant.near',
131
+ amount: '10.00',
132
+ }, chainConfig);
133
+
134
+ const header = near.encodePaymentHeader(payload);
161
135
  ```
162
136
 
163
- ### With the Helper Hook
137
+ ## Wagmi/RainbowKit
164
138
 
165
139
  ```typescript
166
140
  import { useWalletClient } from 'wagmi';
167
- import { useX402Wagmi } from 'uvd-x402-sdk/wagmi';
141
+ import { createPaymentFromWalletClient } from 'uvd-x402-sdk/wagmi';
168
142
 
169
143
  function PayButton() {
170
144
  const { data: walletClient } = useWalletClient();
171
- const { createPayment, isReady } = useX402Wagmi(walletClient);
172
145
 
173
146
  const handlePay = async () => {
174
- const paymentHeader = await createPayment({
175
- recipient: '0xD3868E1eD738CED6945A574a7c769433BeD5d474',
147
+ const paymentHeader = await createPaymentFromWalletClient(walletClient, {
148
+ recipient: '0x...',
176
149
  amount: '10.00',
150
+ chainName: 'base',
177
151
  });
178
152
 
179
153
  await fetch('/api/purchase', {
@@ -181,1353 +155,201 @@ function PayButton() {
181
155
  });
182
156
  };
183
157
 
184
- return (
185
- <button onClick={handlePay} disabled={!isReady}>
186
- Pay $10 USDC
187
- </button>
188
- );
189
- }
190
- ```
191
-
192
- ### Full Example with RainbowKit
193
-
194
- ```tsx
195
- import { ConnectButton } from '@rainbow-me/rainbowkit';
196
- import { useWalletClient, useAccount } from 'wagmi';
197
- import { createPaymentFromWalletClient } from 'uvd-x402-sdk/wagmi';
198
-
199
- function App() {
200
- const { data: walletClient } = useWalletClient();
201
- const { isConnected } = useAccount();
202
-
203
- const handlePurchase = async () => {
204
- if (!walletClient) return;
205
-
206
- try {
207
- const paymentHeader = await createPaymentFromWalletClient(walletClient, {
208
- recipient: '0xD3868E1eD738CED6945A574a7c769433BeD5d474',
209
- amount: '5.00',
210
- chainName: 'base',
211
- });
212
-
213
- const response = await fetch('/api/purchase', {
214
- method: 'POST',
215
- headers: {
216
- 'Content-Type': 'application/json',
217
- 'X-PAYMENT': paymentHeader,
218
- },
219
- body: JSON.stringify({ item: 'premium-feature' }),
220
- });
221
-
222
- if (response.ok) {
223
- alert('Purchase successful!');
224
- }
225
- } catch (error) {
226
- console.error('Payment failed:', error);
227
- }
228
- };
229
-
230
- return (
231
- <div>
232
- <ConnectButton />
233
- {isConnected && (
234
- <button onClick={handlePurchase}>
235
- Buy Premium ($5 USDC)
236
- </button>
237
- )}
238
- </div>
239
- );
158
+ return <button onClick={handlePay}>Pay $10</button>;
240
159
  }
241
160
  ```
242
161
 
243
- ---
244
-
245
- ## Network Examples
246
-
247
- ### EVM Chains (10 Networks)
248
-
249
- All EVM chains use EIP-712 typed data signing with ERC-3009 TransferWithAuthorization.
250
-
251
- #### Base (Recommended - Fastest & Cheapest)
162
+ ## Multi-Stablecoin (EVM)
252
163
 
253
164
  ```typescript
254
- import { X402Client } from 'uvd-x402-sdk';
255
-
256
- const client = new X402Client({ defaultChain: 'base' });
257
-
258
- // Connect to Base
259
- const address = await client.connect('base');
260
- console.log('Connected:', address);
261
-
262
- // Check balance
263
- const balance = await client.getBalance();
264
- console.log('USDC Balance:', balance);
265
-
266
- // Create payment
165
+ // Pay with EURC instead of USDC
267
166
  const result = await client.createPayment({
268
- recipient: '0xD3868E1eD738CED6945A574a7c769433BeD5d474',
167
+ recipient: '0x...',
269
168
  amount: '10.00',
169
+ tokenType: 'eurc', // 'usdc' | 'eurc' | 'ausd' | 'pyusd' | 'usdt'
270
170
  });
271
171
 
272
- console.log('Payment header:', result.paymentHeader);
273
- ```
274
-
275
- #### Ethereum
276
-
277
- ```typescript
278
- import { X402Client } from 'uvd-x402-sdk';
279
-
280
- const client = new X402Client({ defaultChain: 'ethereum' });
281
- const address = await client.connect('ethereum');
172
+ // Check token availability
173
+ import { getSupportedTokens, isTokenSupported } from 'uvd-x402-sdk';
282
174
 
283
- const result = await client.createPayment({
284
- recipient: '0xD3868E1eD738CED6945A574a7c769433BeD5d474',
285
- amount: '100.00', // Higher amounts common on Ethereum
286
- });
175
+ getSupportedTokens('ethereum'); // ['usdc', 'eurc', 'ausd', 'pyusd']
176
+ getSupportedTokens('base'); // ['usdc', 'eurc']
177
+ isTokenSupported('base', 'eurc'); // true
287
178
  ```
288
179
 
289
- #### Polygon
180
+ ## AUSD on Solana (Token2022)
290
181
 
291
182
  ```typescript
292
- import { X402Client } from 'uvd-x402-sdk';
183
+ import { SVMProvider } from 'uvd-x402-sdk/solana';
184
+ import { getChainByName } from 'uvd-x402-sdk';
293
185
 
294
- const client = new X402Client({ defaultChain: 'polygon' });
295
- const address = await client.connect('polygon');
186
+ const svm = new SVMProvider();
187
+ const chainConfig = getChainByName('solana')!;
296
188
 
297
- const result = await client.createPayment({
298
- recipient: '0xD3868E1eD738CED6945A574a7c769433BeD5d474',
189
+ // AUSD uses Token2022 program
190
+ const payload = await svm.signPayment({
191
+ recipient: '5Y32Dk...',
299
192
  amount: '10.00',
300
- });
301
- ```
302
-
303
- #### Arbitrum
304
-
305
- ```typescript
306
- import { X402Client } from 'uvd-x402-sdk';
193
+ token: 'ausd', // Token2022 AUSD
194
+ }, chainConfig);
307
195
 
308
- const client = new X402Client({ defaultChain: 'arbitrum' });
309
- const address = await client.connect('arbitrum');
310
-
311
- const result = await client.createPayment({
312
- recipient: '0xD3868E1eD738CED6945A574a7c769433BeD5d474',
313
- amount: '10.00',
314
- });
196
+ const header = svm.encodePaymentHeader(payload, chainConfig);
315
197
  ```
316
198
 
317
- #### Optimism
318
-
319
- ```typescript
320
- import { X402Client } from 'uvd-x402-sdk';
321
-
322
- const client = new X402Client({ defaultChain: 'optimism' });
323
- const address = await client.connect('optimism');
199
+ ## Supported Networks
324
200
 
325
- const result = await client.createPayment({
326
- recipient: '0xD3868E1eD738CED6945A574a7c769433BeD5d474',
327
- amount: '10.00',
328
- });
329
- ```
201
+ ### EVM (10)
330
202
 
331
- #### Avalanche C-Chain
203
+ | Network | Chain ID | Tokens |
204
+ |---------|----------|--------|
205
+ | Base | 8453 | USDC, EURC |
206
+ | Ethereum | 1 | USDC, EURC, AUSD, PYUSD, USDT |
207
+ | Polygon | 137 | USDC, AUSD |
208
+ | Arbitrum | 42161 | USDC, AUSD, USDT |
209
+ | Optimism | 10 | USDC |
210
+ | Avalanche | 43114 | USDC, EURC, AUSD |
211
+ | Celo | 42220 | USDC |
212
+ | HyperEVM | 999 | USDC |
213
+ | Unichain | 130 | USDC |
214
+ | Monad | 143 | USDC, AUSD |
332
215
 
333
- ```typescript
334
- import { X402Client } from 'uvd-x402-sdk';
216
+ ### SVM (2)
335
217
 
336
- const client = new X402Client({ defaultChain: 'avalanche' });
337
- const address = await client.connect('avalanche');
218
+ | Network | Tokens | Wallet |
219
+ |---------|--------|--------|
220
+ | Solana | USDC, AUSD | Phantom |
221
+ | Fogo | USDC | Phantom |
338
222
 
339
- const result = await client.createPayment({
340
- recipient: '0xD3868E1eD738CED6945A574a7c769433BeD5d474',
341
- amount: '10.00',
342
- });
343
- ```
223
+ ### Algorand (2)
344
224
 
345
- #### Celo
225
+ | Network | USDC ASA | Wallet |
226
+ |---------|----------|--------|
227
+ | Algorand | 31566704 | Lute, Pera |
228
+ | Algorand Testnet | 10458941 | Lute, Pera |
346
229
 
347
- ```typescript
348
- import { X402Client } from 'uvd-x402-sdk';
230
+ ### Other (2)
349
231
 
350
- const client = new X402Client({ defaultChain: 'celo' });
351
- const address = await client.connect('celo');
232
+ | Network | Wallet |
233
+ |---------|--------|
234
+ | Stellar | Freighter |
235
+ | NEAR | MyNearWallet |
352
236
 
353
- const result = await client.createPayment({
354
- recipient: '0xD3868E1eD738CED6945A574a7c769433BeD5d474',
355
- amount: '10.00',
356
- });
357
- ```
237
+ ## Facilitator Addresses
358
238
 
359
- #### HyperEVM
239
+ The SDK includes built-in facilitator addresses. You don't need to configure them.
360
240
 
361
241
  ```typescript
362
- import { X402Client } from 'uvd-x402-sdk';
242
+ import { FACILITATOR_ADDRESSES, getFacilitatorAddress } from 'uvd-x402-sdk';
363
243
 
364
- const client = new X402Client({ defaultChain: 'hyperevm' });
365
- const address = await client.connect('hyperevm');
244
+ // Built-in addresses
245
+ FACILITATOR_ADDRESSES.evm; // 0x103040545AC5031A11E8C03dd11324C7333a13C7
246
+ FACILITATOR_ADDRESSES.solana; // F742C4VfFLQ9zRQyithoj5229ZgtX2WqKCSFKgH2EThq
247
+ FACILITATOR_ADDRESSES.algorand; // KIMS5H6QLCUDL65L5UBTOXDPWLMTS7N3AAC3I6B2NCONEI5QIVK7LH2C2I
248
+ FACILITATOR_ADDRESSES.stellar; // GCHPGXJT2WFFRFCA5TV4G4E3PMMXLNIDUH27PKDYA4QJ2XGYZWGFZNHB
249
+ FACILITATOR_ADDRESSES.near; // uvd-facilitator.near
366
250
 
367
- const result = await client.createPayment({
368
- recipient: '0xD3868E1eD738CED6945A574a7c769433BeD5d474',
369
- amount: '10.00',
370
- });
251
+ // Or get by chain name
252
+ getFacilitatorAddress('algorand'); // KIMS5H6...
253
+ getFacilitatorAddress('base', 'evm'); // 0x1030...
371
254
  ```
372
255
 
373
- #### Unichain
256
+ ## Backend
374
257
 
375
258
  ```typescript
376
- import { X402Client } from 'uvd-x402-sdk';
259
+ import {
260
+ FacilitatorClient,
261
+ create402Response,
262
+ extractPaymentFromHeaders,
263
+ buildPaymentRequirements,
264
+ } from 'uvd-x402-sdk/backend';
377
265
 
378
- const client = new X402Client({ defaultChain: 'unichain' });
379
- const address = await client.connect('unichain');
266
+ // Return 402 if no payment
267
+ app.post('/api/premium', async (req, res) => {
268
+ const payment = extractPaymentFromHeaders(req.headers);
380
269
 
381
- const result = await client.createPayment({
382
- recipient: '0xD3868E1eD738CED6945A574a7c769433BeD5d474',
383
- amount: '10.00',
384
- });
385
- ```
270
+ if (!payment) {
271
+ const { status, headers, body } = create402Response({
272
+ amount: '1.00',
273
+ recipient: process.env.RECIPIENT,
274
+ resource: 'https://api.example.com/premium',
275
+ chainName: 'base',
276
+ });
277
+ return res.status(status).set(headers).json(body);
278
+ }
386
279
 
387
- #### Monad
280
+ // Verify and settle
281
+ const client = new FacilitatorClient();
282
+ const requirements = buildPaymentRequirements({
283
+ amount: '1.00',
284
+ recipient: process.env.RECIPIENT,
285
+ });
388
286
 
389
- ```typescript
390
- import { X402Client } from 'uvd-x402-sdk';
287
+ const result = await client.verifyAndSettle(payment, requirements);
391
288
 
392
- const client = new X402Client({ defaultChain: 'monad' });
393
- const address = await client.connect('monad');
289
+ if (!result.verified) {
290
+ return res.status(402).json({ error: result.error });
291
+ }
394
292
 
395
- const result = await client.createPayment({
396
- recipient: '0xD3868E1eD738CED6945A574a7c769433BeD5d474',
397
- amount: '10.00',
293
+ res.json({ data: 'premium content', txHash: result.transactionHash });
398
294
  });
399
295
  ```
400
296
 
401
- ---
402
-
403
- ### SVM Chains (Solana Virtual Machine)
404
-
405
- SVM chains use partially-signed transactions where the facilitator is the fee payer.
406
-
407
- #### Solana
408
-
409
- ```typescript
410
- import { SVMProvider } from 'uvd-x402-sdk/solana';
411
- import { getChainByName } from 'uvd-x402-sdk';
297
+ ## React
412
298
 
413
- const svm = new SVMProvider();
299
+ ```tsx
300
+ import { X402Provider, useX402, usePayment } from 'uvd-x402-sdk/react';
414
301
 
415
- // Check if Phantom is installed
416
- if (!svm.isAvailable()) {
417
- throw new Error('Please install Phantom wallet from phantom.app');
302
+ function App() {
303
+ return (
304
+ <X402Provider config={{ defaultChain: 'base' }}>
305
+ <PaymentPage />
306
+ </X402Provider>
307
+ );
418
308
  }
419
309
 
420
- // Connect
421
- const address = await svm.connect();
422
- console.log('Connected Solana wallet:', address);
423
-
424
- // Get chain config
425
- const chainConfig = getChainByName('solana')!;
426
-
427
- // Get balance
428
- const balance = await svm.getBalance(chainConfig);
429
- console.log('USDC Balance:', balance);
430
-
431
- // Create payment
432
- const paymentPayload = await svm.signPayment(
433
- {
434
- recipient: '5Y32Dk6weq1LrMRdujpJyDbTN3SjwXGoQS9QN39WQ9Cq',
435
- amount: '10.00',
436
- facilitator: 'F742C4VfFLQ9zRQyithoj5229ZgtX2WqKCSFKgH2EThq',
437
- },
438
- chainConfig
439
- );
440
-
441
- // Encode as X-PAYMENT header
442
- const header = svm.encodePaymentHeader(paymentPayload, chainConfig);
443
- console.log('Payment header:', header);
444
- ```
445
-
446
- #### Fogo
447
-
448
- Fogo is an SVM chain with ultra-fast ~400ms finality.
449
-
450
- ```typescript
451
- import { SVMProvider } from 'uvd-x402-sdk/solana';
452
- import { getChainByName } from 'uvd-x402-sdk';
453
-
454
- const svm = new SVMProvider();
310
+ function PaymentPage() {
311
+ const { connect, isConnected, address } = useX402();
312
+ const { pay, isPaying } = usePayment();
455
313
 
456
- // Connect (same wallet works for all SVM chains)
457
- const address = await svm.connect();
314
+ if (!isConnected) {
315
+ return <button onClick={() => connect('base')}>Connect</button>;
316
+ }
458
317
 
459
- // Get Fogo chain config
460
- const chainConfig = getChainByName('fogo')!;
461
-
462
- // Get balance on Fogo
463
- const balance = await svm.getBalance(chainConfig);
464
- console.log('Fogo USDC Balance:', balance);
465
-
466
- // Create Fogo payment
467
- const paymentPayload = await svm.signPayment(
468
- {
469
- recipient: '5Y32Dk6weq1LrMRdujpJyDbTN3SjwXGoQS9QN39WQ9Cq',
470
- amount: '10.00',
471
- facilitator: 'F742C4VfFLQ9zRQyithoj5229ZgtX2WqKCSFKgH2EThq',
472
- },
473
- chainConfig
474
- );
475
-
476
- // Encode with correct network name ('fogo')
477
- const header = svm.encodePaymentHeader(paymentPayload, chainConfig);
478
- console.log('Fogo payment header:', header);
318
+ return (
319
+ <button onClick={() => pay({ recipient: '0x...', amount: '10.00' })} disabled={isPaying}>
320
+ {isPaying ? 'Processing...' : 'Pay $10'}
321
+ </button>
322
+ );
323
+ }
479
324
  ```
480
325
 
481
- ---
482
-
483
- ### Stellar
484
-
485
- Stellar uses Soroban authorization entries for gasless transfers.
326
+ ## Error Handling
486
327
 
487
328
  ```typescript
488
- import { StellarProvider } from 'uvd-x402-sdk/stellar';
489
- import { getChainByName } from 'uvd-x402-sdk';
490
-
491
- const stellar = new StellarProvider();
329
+ import { X402Error } from 'uvd-x402-sdk';
492
330
 
493
- // Check if Freighter is installed
494
- if (!stellar.isAvailable()) {
495
- throw new Error('Please install Freighter wallet from freighter.app');
331
+ try {
332
+ await client.createPayment(paymentInfo);
333
+ } catch (error) {
334
+ if (error instanceof X402Error) {
335
+ switch (error.code) {
336
+ case 'WALLET_NOT_FOUND': // Install wallet
337
+ case 'WALLET_CONNECTION_REJECTED': // User rejected
338
+ case 'INSUFFICIENT_BALANCE': // Not enough USDC
339
+ case 'SIGNATURE_REJECTED': // User cancelled
340
+ case 'CHAIN_NOT_SUPPORTED': // Unsupported network
341
+ }
342
+ }
496
343
  }
497
-
498
- // Connect
499
- const address = await stellar.connect();
500
- console.log('Connected Stellar wallet:', address);
501
-
502
- // Get chain config
503
- const chainConfig = getChainByName('stellar')!;
504
-
505
- // Get balance
506
- const balance = await stellar.getBalance(chainConfig);
507
- console.log('USDC Balance:', balance);
508
-
509
- // Create payment
510
- const paymentPayload = await stellar.signPayment(
511
- {
512
- recipient: 'GD3FWQ4QFSCO2F2KVXZPQWOC27CQHXHYCRCRRZBMWU3DNOZW2IIGOU54',
513
- amount: '10.00',
514
- },
515
- chainConfig
516
- );
517
-
518
- // Encode as X-PAYMENT header
519
- const header = stellar.encodePaymentHeader(paymentPayload);
520
- console.log('Payment header:', header);
521
344
  ```
522
345
 
523
- ---
346
+ ## Links
524
347
 
525
- ### NEAR Protocol
348
+ - [x402 Protocol](https://x402.org)
349
+ - [Ultravioleta DAO](https://ultravioletadao.xyz)
350
+ - [npm](https://www.npmjs.com/package/uvd-x402-sdk)
351
+ - [GitHub](https://github.com/UltravioletaDAO/uvd-x402-sdk-typescript)
526
352
 
527
- NEAR uses NEP-366 meta-transactions where the facilitator pays all gas.
353
+ ## License
528
354
 
529
- ```typescript
530
- import { NEARProvider } from 'uvd-x402-sdk/near';
531
- import { getChainByName } from 'uvd-x402-sdk';
532
-
533
- const near = new NEARProvider();
534
-
535
- // Check if NEAR wallet is available
536
- if (!near.isAvailable()) {
537
- throw new Error('Please install MyNearWallet or Meteor wallet');
538
- }
539
-
540
- // Connect
541
- const accountId = await near.connect();
542
- console.log('Connected NEAR account:', accountId);
543
-
544
- // Get chain config
545
- const chainConfig = getChainByName('near')!;
546
-
547
- // Get balance
548
- const balance = await near.getBalance(chainConfig);
549
- console.log('USDC Balance:', balance);
550
-
551
- // Create payment
552
- const paymentPayload = await near.signPayment(
553
- {
554
- recipient: '0xultravioleta.near',
555
- amount: '10.00',
556
- },
557
- chainConfig
558
- );
559
-
560
- // Encode as X-PAYMENT header
561
- const header = near.encodePaymentHeader(paymentPayload);
562
- console.log('Payment header:', header);
563
- ```
564
-
565
- ---
566
-
567
- ## x402 Protocol Versions
568
-
569
- The SDK supports both x402 v1 and v2 protocols.
570
-
571
- ### v1 (Default)
572
-
573
- ```typescript
574
- // v1 uses simple network names
575
- {
576
- "x402Version": 1,
577
- "scheme": "exact",
578
- "network": "base",
579
- "payload": { ... }
580
- }
581
- ```
582
-
583
- ### v2 (CAIP-2)
584
-
585
- ```typescript
586
- // v2 uses CAIP-2 chain identifiers
587
- {
588
- "x402Version": 2,
589
- "scheme": "exact",
590
- "network": "eip155:8453",
591
- "payload": { ... },
592
- "accepts": [
593
- { "network": "eip155:8453", "asset": "0x833...", "amount": "10000000" },
594
- { "network": "solana:5eykt...", "asset": "EPjF...", "amount": "10000000" }
595
- ]
596
- }
597
- ```
598
-
599
- ### Version Detection and Conversion
600
-
601
- ```typescript
602
- import {
603
- detectX402Version,
604
- chainToCAIP2,
605
- caip2ToChain,
606
- convertX402Header,
607
- } from 'uvd-x402-sdk';
608
-
609
- // Detect version from response
610
- const version = detectX402Version(response402);
611
- // Returns: 1 or 2
612
-
613
- // Convert between formats
614
- const caip2 = chainToCAIP2('base');
615
- // Returns: 'eip155:8453'
616
-
617
- const chainName = caip2ToChain('eip155:8453');
618
- // Returns: 'base'
619
-
620
- // Convert headers between versions
621
- const v2Header = convertX402Header(v1Header, 2);
622
- ```
623
-
624
- ### Configure Version
625
-
626
- ```typescript
627
- const client = new X402Client({
628
- defaultChain: 'base',
629
- x402Version: 2, // Force v2 format
630
- // or
631
- x402Version: 'auto', // Auto-detect from 402 response (default)
632
- });
633
- ```
634
-
635
- ---
636
-
637
- ## Multi-Payment Support
638
-
639
- Accept payments on multiple networks simultaneously.
640
-
641
- ### Configuration
642
-
643
- ```typescript
644
- const client = new X402Client({
645
- defaultChain: 'base',
646
- multiPayment: {
647
- networks: ['base', 'solana', 'stellar', 'near'],
648
- defaultNetwork: 'base',
649
- autoDetect: true, // Auto-select based on user's wallet
650
- },
651
- });
652
- ```
653
-
654
- ### Generate Payment Options
655
-
656
- ```typescript
657
- import { generatePaymentOptions, getEnabledChains } from 'uvd-x402-sdk';
658
-
659
- // Get all enabled chain configs
660
- const chains = getEnabledChains();
661
-
662
- // Generate v2 payment options
663
- const options = generatePaymentOptions(chains, '10.00');
664
-
665
- // Result:
666
- // [
667
- // { network: 'eip155:8453', asset: '0x833...', amount: '10000000' },
668
- // { network: 'solana:5eykt...', asset: 'EPjF...', amount: '10000000' },
669
- // { network: 'stellar:pubnet', asset: 'CCW67...', amount: '100000000' },
670
- // { network: 'near:mainnet', asset: '17208...', amount: '10000000' },
671
- // ]
672
- ```
673
-
674
- ---
675
-
676
- ## Multi-Stablecoin Support (EVM)
677
-
678
- EVM chains support multiple stablecoins beyond USDC. Token availability varies by chain.
679
-
680
- ### Supported Tokens
681
-
682
- | Token | Description | Decimals | Chains |
683
- |-------|-------------|----------|--------|
684
- | USDC | USD Coin (Circle) | 6 | All EVM chains |
685
- | EURC | Euro Coin (Circle) | 6 | Ethereum, Base, Avalanche |
686
- | AUSD | Agora Dollar | 6 | Ethereum, Avalanche, Polygon, Arbitrum, Monad |
687
- | PYUSD | PayPal USD | 6 | Ethereum |
688
- | USDT | Tether USD (USDT0 Omnichain via LayerZero) | 6 | Ethereum, Arbitrum |
689
-
690
- ### Basic Usage
691
-
692
- ```typescript
693
- import { X402Client } from 'uvd-x402-sdk';
694
-
695
- const client = new X402Client({ defaultChain: 'base' });
696
- await client.connect('base');
697
-
698
- // Pay with EURC instead of USDC
699
- const result = await client.createPayment({
700
- recipient: '0xD3868E1eD738CED6945A574a7c769433BeD5d474',
701
- amount: '10.00',
702
- tokenType: 'eurc', // 'usdc' | 'eurc' | 'ausd' | 'pyusd'
703
- });
704
- ```
705
-
706
- ### Check Token Availability
707
-
708
- ```typescript
709
- import {
710
- getSupportedTokens,
711
- isTokenSupported,
712
- getTokenConfig,
713
- getChainsByToken,
714
- } from 'uvd-x402-sdk';
715
-
716
- // Get all tokens supported on a chain
717
- const tokens = getSupportedTokens('ethereum');
718
- // Returns: ['usdc', 'eurc', 'ausd', 'pyusd']
719
-
720
- const baseTokens = getSupportedTokens('base');
721
- // Returns: ['usdc', 'eurc']
722
-
723
- // Check if a specific token is supported
724
- if (isTokenSupported('base', 'eurc')) {
725
- console.log('EURC available on Base');
726
- }
727
-
728
- // Get token configuration (address, decimals, name)
729
- const eurcConfig = getTokenConfig('ethereum', 'eurc');
730
- // Returns: { address: '0x1aBa...', decimals: 6, name: 'EURC', version: '2' }
731
-
732
- // Find all chains that support a token
733
- const eurcChains = getChainsByToken('eurc');
734
- // Returns: [baseConfig, ethereumConfig, avalancheConfig]
735
- ```
736
-
737
- ### Check Token Balance
738
-
739
- ```typescript
740
- import { EVMProvider } from 'uvd-x402-sdk';
741
- import { getChainByName } from 'uvd-x402-sdk';
742
-
743
- const evm = new EVMProvider();
744
- await evm.connect();
745
-
746
- const chainConfig = getChainByName('ethereum')!;
747
-
748
- // Check USDC balance (default)
749
- const usdcBalance = await evm.getBalance(chainConfig);
750
-
751
- // Check EURC balance
752
- const eurcBalance = await evm.getBalance(chainConfig, 'eurc');
753
-
754
- // Check PYUSD balance
755
- const pyusdBalance = await evm.getBalance(chainConfig, 'pyusd');
756
- ```
757
-
758
- ### Wagmi/RainbowKit with Multi-Token
759
-
760
- ```typescript
761
- import { useWalletClient } from 'wagmi';
762
- import { createPaymentFromWalletClient } from 'uvd-x402-sdk/wagmi';
763
-
764
- function PayWithEURC() {
765
- const { data: walletClient } = useWalletClient();
766
-
767
- const handlePay = async () => {
768
- const paymentHeader = await createPaymentFromWalletClient(walletClient, {
769
- recipient: '0xD3868E1eD738CED6945A574a7c769433BeD5d474',
770
- amount: '10.00',
771
- chainName: 'base',
772
- tokenType: 'eurc', // Pay with EURC
773
- });
774
-
775
- await fetch('/api/purchase', {
776
- headers: { 'X-PAYMENT': paymentHeader },
777
- method: 'POST',
778
- });
779
- };
780
-
781
- return <button onClick={handlePay}>Pay 10 EURC</button>;
782
- }
783
- ```
784
-
785
- ### Critical Implementation Notes
786
-
787
- #### EIP-712 Domain Names Vary by Chain
788
-
789
- The same token may use **different EIP-712 domain names on different chains**. This affects signature verification.
790
-
791
- | Token | Ethereum | Base | Avalanche |
792
- |-------|----------|------|-----------|
793
- | EURC | `"Euro Coin"` | `"EURC"` | `"Euro Coin"` |
794
- | USDC | `"USD Coin"` | `"USD Coin"` | `"USD Coin"` |
795
- | AUSD | `"AUSD"` | N/A | `"AUSD"` |
796
- | PYUSD | `"PayPal USD"` | N/A | N/A |
797
-
798
- **Important:** Always use `getTokenConfig()` to get the correct domain name for each chain. Never hardcode domain names.
799
-
800
- ```typescript
801
- // CORRECT: Use getTokenConfig for each chain
802
- const eurcBase = getTokenConfig('base', 'eurc');
803
- // Returns: { name: 'EURC', version: '2', ... }
804
-
805
- const eurcEthereum = getTokenConfig('ethereum', 'eurc');
806
- // Returns: { name: 'Euro Coin', version: '2', ... }
807
- ```
808
-
809
- #### PYUSD Signature Format (PayPal USD)
810
-
811
- PYUSD uses the Paxos implementation which only supports the **v,r,s signature variant** of `transferWithAuthorization`. This is different from Circle's USDC/EURC which support both compact bytes and v,r,s variants.
812
-
813
- **Backend implications:**
814
- - The x402 facilitator (v1.9.0+) automatically handles this by detecting PYUSD and using `transferWithAuthorization_1(v,r,s)` instead of `transferWithAuthorization_0(bytes signature)`
815
- - If using a custom facilitator, ensure it supports the v,r,s variant for PYUSD
816
-
817
- #### Token Info Must Be Passed to Backend
818
-
819
- When using non-USDC tokens, you **must** pass the token info in your payment payload so the backend can validate the correct EIP-712 domain. The SDK handles this automatically when you specify `tokenType`.
820
-
821
- ```typescript
822
- // The SDK automatically includes token info when you specify tokenType
823
- const paymentHeader = await client.createPayment({
824
- recipient: '0x...',
825
- amount: '10.00',
826
- tokenType: 'eurc', // This ensures token info is included
827
- });
828
-
829
- // Backend receives token info in the payload:
830
- // {
831
- // "token": {
832
- // "address": "0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42",
833
- // "symbol": "EURC",
834
- // "decimals": 6,
835
- // "eip712": { "name": "EURC", "version": "2" }
836
- // }
837
- // }
838
- ```
839
-
840
- ---
841
-
842
- ## React Integration
843
-
844
- ```tsx
845
- import { X402Provider, useX402, usePayment, useBalance } from 'uvd-x402-sdk/react';
846
-
847
- function App() {
848
- return (
849
- <X402Provider config={{ defaultChain: 'base' }}>
850
- <PaymentPage />
851
- </X402Provider>
852
- );
853
- }
854
-
855
- function PaymentPage() {
856
- const { connect, disconnect, isConnected, address, network } = useX402();
857
- const { balance, isLoading: balanceLoading } = useBalance();
858
- const { pay, isPaying, error } = usePayment();
859
-
860
- const handlePurchase = async () => {
861
- const result = await pay({
862
- recipient: '0xD3868E1eD738CED6945A574a7c769433BeD5d474',
863
- amount: '10.00',
864
- });
865
-
866
- await fetch('/api/purchase', {
867
- headers: { 'X-PAYMENT': result.paymentHeader },
868
- method: 'POST',
869
- body: JSON.stringify({ item: 'premium' }),
870
- });
871
- };
872
-
873
- if (!isConnected) {
874
- return <button onClick={() => connect('base')}>Connect Wallet</button>;
875
- }
876
-
877
- return (
878
- <div>
879
- <p>Connected: {address}</p>
880
- <p>Network: {network}</p>
881
- <p>Balance: {balanceLoading ? 'Loading...' : `${balance} USDC`}</p>
882
- <button onClick={handlePurchase} disabled={isPaying}>
883
- {isPaying ? 'Processing...' : 'Pay $10 USDC'}
884
- </button>
885
- {error && <p style={{ color: 'red' }}>{error}</p>}
886
- </div>
887
- );
888
- }
889
- ```
890
-
891
- ---
892
-
893
- ## Supported Networks
894
-
895
- ### EVM Networks (10)
896
-
897
- | Network | Chain ID | Tokens | Status |
898
- |---------|----------|--------|--------|
899
- | Ethereum | 1 | USDC, EURC, AUSD, PYUSD | Enabled |
900
- | Base | 8453 | USDC, EURC | Enabled |
901
- | Avalanche | 43114 | USDC, EURC, AUSD | Enabled |
902
- | Arbitrum | 42161 | USDC, AUSD | Enabled |
903
- | Polygon | 137 | USDC, AUSD | Enabled |
904
- | Monad | 143 | USDC, AUSD | Enabled |
905
- | Optimism | 10 | USDC | Enabled |
906
- | Celo | 42220 | USDC | Enabled |
907
- | HyperEVM | 999 | USDC | Enabled |
908
- | Unichain | 130 | USDC | Enabled |
909
-
910
- ### SVM Networks (2)
911
-
912
- | Network | USDC Mint | Decimals | Wallet | Status |
913
- |---------|-----------|----------|--------|--------|
914
- | Solana | EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v | 6 | Phantom | Enabled |
915
- | Fogo | uSd2czE61Evaf76RNbq4KPpXnkiL3irdzgLFUMe3NoG | 6 | Phantom | Enabled |
916
-
917
- ### Other Networks (2)
918
-
919
- | Network | USDC Address | Decimals | Wallet | Status |
920
- |---------|--------------|----------|--------|--------|
921
- | Stellar | CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75 | 7 | Freighter | Enabled |
922
- | NEAR | 17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1 | 6 | MyNearWallet | Enabled |
923
-
924
- ---
925
-
926
- ## API Reference
927
-
928
- ### X402Client
929
-
930
- ```typescript
931
- const client = new X402Client(config?: X402ClientConfig);
932
-
933
- interface X402ClientConfig {
934
- facilitatorUrl?: string; // Default: 'https://facilitator.ultravioletadao.xyz'
935
- defaultChain?: string; // Default: 'base'
936
- autoConnect?: boolean; // Default: false
937
- debug?: boolean; // Default: false
938
- x402Version?: 1 | 2 | 'auto'; // Default: 'auto'
939
- customChains?: Record<string, Partial<ChainConfig>>;
940
- rpcOverrides?: Record<string, string>;
941
- multiPayment?: MultiPaymentConfig;
942
- }
943
- ```
944
-
945
- #### Methods
946
-
947
- | Method | Description |
948
- |--------|-------------|
949
- | `connect(chainName?)` | Connect wallet to specified chain |
950
- | `disconnect()` | Disconnect current wallet |
951
- | `switchChain(chainName)` | Switch to different EVM chain |
952
- | `createPayment(paymentInfo)` | Create payment authorization (supports `tokenType` in paymentInfo) |
953
- | `getBalance(tokenType?)` | Get token balance on current chain (defaults to USDC) |
954
- | `getState()` | Get current wallet state |
955
- | `isConnected()` | Check if wallet is connected |
956
- | `on(event, handler)` | Subscribe to events |
957
-
958
- ### Chain Utilities
959
-
960
- ```typescript
961
- import {
962
- SUPPORTED_CHAINS,
963
- getChainByName,
964
- getChainById,
965
- getEnabledChains,
966
- getChainsByNetworkType,
967
- getSVMChains,
968
- isSVMChain,
969
- getExplorerTxUrl,
970
- getExplorerAddressUrl,
971
- // Multi-token utilities
972
- getTokenConfig,
973
- getSupportedTokens,
974
- isTokenSupported,
975
- getChainsByToken,
976
- } from 'uvd-x402-sdk';
977
- ```
978
-
979
- ### Token Utilities
980
-
981
- | Function | Description |
982
- |----------|-------------|
983
- | `getTokenConfig(chain, tokenType)` | Get token config (address, decimals, name, version) |
984
- | `getSupportedTokens(chain)` | Get array of supported token types for a chain |
985
- | `isTokenSupported(chain, tokenType)` | Check if token is available on chain |
986
- | `getChainsByToken(tokenType)` | Get all chains that support a specific token |
987
-
988
- ### x402 Utilities
989
-
990
- ```typescript
991
- import {
992
- detectX402Version,
993
- chainToCAIP2,
994
- caip2ToChain,
995
- createX402V1Header,
996
- createX402V2Header,
997
- encodeX402Header,
998
- decodeX402Header,
999
- convertX402Header,
1000
- generatePaymentOptions,
1001
- } from 'uvd-x402-sdk';
1002
- ```
1003
-
1004
- ### Wagmi Adapter
1005
-
1006
- ```typescript
1007
- import {
1008
- createPaymentFromWalletClient,
1009
- createPaymentWithResult,
1010
- useX402Wagmi,
1011
- } from 'uvd-x402-sdk/wagmi';
1012
- ```
1013
-
1014
- | Function | Description |
1015
- |----------|-------------|
1016
- | `createPaymentFromWalletClient(walletClient, options)` | Create payment header using wagmi's WalletClient |
1017
- | `createPaymentWithResult(walletClient, options)` | Same as above but returns full PaymentResult |
1018
- | `useX402Wagmi(walletClient)` | Helper hook returning `{ createPayment, isReady }` |
1019
-
1020
- #### Options
1021
-
1022
- ```typescript
1023
- interface WagmiPaymentOptions {
1024
- recipient: string; // Recipient address
1025
- amount: string; // Amount in token (e.g., "10.00")
1026
- chainName?: string; // Chain name (default: 'base')
1027
- tokenType?: TokenType; // Token type (default: 'usdc')
1028
- validitySeconds?: number; // Signature validity window (default: 300)
1029
- }
1030
- ```
1031
-
1032
- ---
1033
-
1034
- ## Error Handling
1035
-
1036
- ```typescript
1037
- import { X402Error } from 'uvd-x402-sdk';
1038
-
1039
- try {
1040
- await client.createPayment(paymentInfo);
1041
- } catch (error) {
1042
- if (error instanceof X402Error) {
1043
- switch (error.code) {
1044
- case 'WALLET_NOT_FOUND':
1045
- alert('Please install a wallet');
1046
- break;
1047
- case 'WALLET_CONNECTION_REJECTED':
1048
- alert('Connection cancelled');
1049
- break;
1050
- case 'INSUFFICIENT_BALANCE':
1051
- alert('Not enough USDC');
1052
- break;
1053
- case 'SIGNATURE_REJECTED':
1054
- alert('Payment cancelled');
1055
- break;
1056
- case 'CHAIN_NOT_SUPPORTED':
1057
- alert('Network not supported');
1058
- break;
1059
- default:
1060
- alert(error.message);
1061
- }
1062
- }
1063
- }
1064
- ```
1065
-
1066
- ### Error Codes
1067
-
1068
- | Code | Description |
1069
- |------|-------------|
1070
- | `WALLET_NOT_FOUND` | No compatible wallet detected |
1071
- | `WALLET_NOT_CONNECTED` | Wallet not connected |
1072
- | `WALLET_CONNECTION_REJECTED` | User rejected connection |
1073
- | `CHAIN_NOT_SUPPORTED` | Chain not supported |
1074
- | `CHAIN_SWITCH_REJECTED` | User rejected chain switch |
1075
- | `INSUFFICIENT_BALANCE` | Not enough USDC |
1076
- | `SIGNATURE_REJECTED` | User rejected signature |
1077
- | `PAYMENT_FAILED` | Payment processing failed |
1078
- | `NETWORK_ERROR` | Network request failed |
1079
- | `INVALID_CONFIG` | Invalid configuration |
1080
-
1081
- ---
1082
-
1083
- ## Backend Utilities
1084
-
1085
- The SDK includes comprehensive server-side utilities for handling x402 payments.
1086
-
1087
- ### Payment Flow Diagram
1088
-
1089
- ```
1090
- ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ ┌──────────────┐
1091
- │ Client │ │ Your API │ │ Facilitator │ │ Blockchain │
1092
- └──────┬──────┘ └──────┬──────┘ └────────┬────────┘ └──────┬───────┘
1093
- │ │ │ │
1094
- │ 1. Request resource (no payment) │ │
1095
- │ ────────────────> │ │ │
1096
- │ │ │ │
1097
- │ 2. 402 Payment Required │ │
1098
- │ <──────────────── │ │ │
1099
- │ │ │ │
1100
- │ 3. User signs payment │ │
1101
- │ (wallet popup) │ │ │
1102
- │ │ │ │
1103
- │ 4. Request with X-PAYMENT header │ │
1104
- │ ────────────────> │ │ │
1105
- │ │ │ │
1106
- │ │ 5. Verify payment │ │
1107
- │ │ ────────────────────> │
1108
- │ │ │ │
1109
- │ │ 6. Payment valid │ │
1110
- │ │ <────────────────── │ │
1111
- │ │ │ │
1112
- │ 7. Provide resource │ │
1113
- │ <──────────────── │ │ │
1114
- │ │ │ │
1115
- │ │ 8. Settle payment │ │
1116
- │ │ ────────────────────> │
1117
- │ │ │ │
1118
- │ │ │ 9. Submit tx │
1119
- │ │ │ ───────────────────>│
1120
- │ │ │ │
1121
- │ │ │ 10. Confirmed │
1122
- │ │ │ <───────────────────│
1123
- │ │ │ │
1124
- │ │ 11. Settlement done │ │
1125
- │ │ <────────────────── │ │
1126
- └ └ └ └
1127
- ```
1128
-
1129
- ### Basic Backend Setup
1130
-
1131
- ```typescript
1132
- import {
1133
- parsePaymentHeader,
1134
- extractPaymentFromHeaders,
1135
- buildPaymentRequirements,
1136
- FacilitatorClient,
1137
- create402Response,
1138
- X402_CORS_HEADERS,
1139
- } from 'uvd-x402-sdk/backend';
1140
-
1141
- // Configure CORS
1142
- app.use((req, res, next) => {
1143
- Object.entries(X402_CORS_HEADERS).forEach(([key, value]) => {
1144
- res.setHeader(key, value);
1145
- });
1146
- next();
1147
- });
1148
-
1149
- // Protected endpoint
1150
- app.post('/api/premium', async (req, res) => {
1151
- // Extract payment from headers
1152
- const payment = extractPaymentFromHeaders(req.headers);
1153
-
1154
- if (!payment) {
1155
- // Return 402 Payment Required
1156
- const { status, headers, body } = create402Response({
1157
- amount: '1.00',
1158
- recipient: process.env.PAYMENT_RECIPIENT,
1159
- resource: 'https://api.example.com/premium',
1160
- chainName: 'base',
1161
- });
1162
- return res.status(status).set(headers).json(body);
1163
- }
1164
-
1165
- // Verify payment with facilitator
1166
- const client = new FacilitatorClient();
1167
- const requirements = buildPaymentRequirements({
1168
- amount: '1.00',
1169
- recipient: process.env.PAYMENT_RECIPIENT,
1170
- resource: 'https://api.example.com/premium',
1171
- });
1172
-
1173
- const verifyResult = await client.verify(payment, requirements);
1174
-
1175
- if (!verifyResult.isValid) {
1176
- return res.status(402).json({
1177
- error: 'Payment verification failed',
1178
- reason: verifyResult.invalidReason,
1179
- });
1180
- }
1181
-
1182
- // Provide the resource
1183
- res.json({ data: 'premium content' });
1184
-
1185
- // Settle payment after response
1186
- await client.settle(payment, requirements);
1187
- });
1188
- ```
1189
-
1190
- ### Using Payment Middleware
1191
-
1192
- ```typescript
1193
- import { createPaymentMiddleware } from 'uvd-x402-sdk/backend';
1194
-
1195
- const paymentMiddleware = createPaymentMiddleware(
1196
- (req) => ({
1197
- amount: '1.00',
1198
- recipient: process.env.PAYMENT_RECIPIENT,
1199
- resource: `${req.protocol}://${req.get('host')}${req.originalUrl}`,
1200
- })
1201
- );
1202
-
1203
- // Apply to specific routes
1204
- app.get('/premium/*', paymentMiddleware, (req, res) => {
1205
- res.json({ premium: 'data' });
1206
- });
1207
- ```
1208
-
1209
- ### FacilitatorClient API
1210
-
1211
- ```typescript
1212
- const client = new FacilitatorClient({
1213
- baseUrl: 'https://facilitator.ultravioletadao.xyz', // default
1214
- timeout: 30000, // default: 30 seconds
1215
- });
1216
-
1217
- // Verify a payment
1218
- const verifyResult = await client.verify(payment, requirements);
1219
- // Returns: { isValid: boolean, invalidReason?: string, payer?: string }
1220
-
1221
- // Settle a payment (execute on-chain)
1222
- const settleResult = await client.settle(payment, requirements);
1223
- // Returns: { success: boolean, transactionHash?: string, error?: string }
1224
-
1225
- // Combined verify + settle
1226
- const result = await client.verifyAndSettle(payment, requirements);
1227
- // Returns: { verified: boolean, settled: boolean, transactionHash?: string, error?: string }
1228
-
1229
- // Health check
1230
- const isHealthy = await client.healthCheck();
1231
- ```
1232
-
1233
- ---
1234
-
1235
- ## Bazaar Discovery API
1236
-
1237
- Discover and register x402-enabled resources across the ecosystem.
1238
-
1239
- ```typescript
1240
- import { BazaarClient } from 'uvd-x402-sdk/backend';
1241
-
1242
- // Discover resources (no auth required)
1243
- const bazaar = new BazaarClient();
1244
-
1245
- const results = await bazaar.discover({
1246
- category: 'ai', // 'api' | 'data' | 'ai' | 'media' | 'compute' | 'storage'
1247
- network: 'base', // Filter by network
1248
- token: 'USDC', // Filter by token
1249
- maxPrice: '0.10', // Max price in dollars
1250
- query: 'image', // Search query
1251
- sortBy: 'price', // 'price' | 'createdAt' | 'name'
1252
- sortOrder: 'asc',
1253
- });
1254
-
1255
- for (const resource of results.resources) {
1256
- console.log(`${resource.name}: ${resource.url} - $${resource.pricePerRequest}`);
1257
- }
1258
- ```
1259
-
1260
- ### Register a Resource
1261
-
1262
- ```typescript
1263
- // Registration requires API key
1264
- const bazaar = new BazaarClient({
1265
- apiKey: process.env.BAZAAR_API_KEY,
1266
- });
1267
-
1268
- const resource = await bazaar.register({
1269
- url: 'https://api.example.com/v1/generate',
1270
- name: 'AI Image Generator',
1271
- description: 'Generate high-quality images with AI',
1272
- category: 'ai',
1273
- networks: ['base', 'ethereum', 'polygon'],
1274
- tokens: ['USDC', 'EURC'],
1275
- price: '0.05',
1276
- payTo: '0xD3868E1eD738CED6945A574a7c769433BeD5d474',
1277
- tags: ['ai', 'image', 'generator'],
1278
- });
1279
-
1280
- console.log('Registered:', resource.id);
1281
-
1282
- // Update resource
1283
- await bazaar.update(resource.id, { price: '0.03' });
1284
-
1285
- // Deactivate (soft delete)
1286
- await bazaar.deactivate(resource.id);
1287
-
1288
- // Reactivate
1289
- await bazaar.reactivate(resource.id);
1290
-
1291
- // Delete permanently
1292
- await bazaar.delete(resource.id);
1293
- ```
1294
-
1295
- ### List Your Resources
1296
-
1297
- ```typescript
1298
- const myResources = await bazaar.listMyResources({
1299
- includeInactive: true,
1300
- });
1301
- ```
1302
-
1303
- ---
1304
-
1305
- ## Escrow & Refunds
1306
-
1307
- For services that may require refunds, use the escrow system.
1308
-
1309
- ### Escrow Flow Diagram
1310
-
1311
- ```
1312
- ┌─────────────┐ ┌─────────────┐ ┌──────────────────┐ ┌──────────────┐
1313
- │ Payer │ │ Your API │ │ Escrow Service │ │ Blockchain │
1314
- └──────┬──────┘ └──────┬──────┘ └────────┬─────────┘ └──────┬───────┘
1315
- │ │ │ │
1316
- │ 1. Pay with X-PAYMENT │ │
1317
- │ ────────────────> │ │ │
1318
- │ │ │ │
1319
- │ │ 2. Create escrow │ │
1320
- │ │ ────────────────────> │
1321
- │ │ │ │
1322
- │ │ │ 3. Hold funds │
1323
- │ │ │ ─────────────────────>
1324
- │ │ │ │
1325
- │ │ 4. Escrow created │ │
1326
- │ │ <────────────────── │ │
1327
- │ │ │ │
1328
- │ 5. Provide service │ │
1329
- │ <──────────────── │ │ │
1330
- │ │ │ │
1331
- │ ┌───────────────────────────────────────────────────────────┐
1332
- │ │ IF SERVICE DELIVERED │
1333
- │ └───────────────────────────────────────────────────────────┘
1334
- │ │ 6a. Release escrow │ │
1335
- │ │ ────────────────────> │
1336
- │ │ │ │
1337
- │ │ │ 7a. Transfer to │
1338
- │ │ │ recipient │
1339
- │ │ │ ─────────────────────>
1340
- │ │ │ │
1341
- │ ┌───────────────────────────────────────────────────────────┐
1342
- │ │ IF SERVICE FAILED │
1343
- │ └───────────────────────────────────────────────────────────┘
1344
- │ 6b. Request refund│ │ │
1345
- │ ────────────────> │ │ │
1346
- │ │ 7b. Process refund │ │
1347
- │ │ ────────────────────> │
1348
- │ │ │ │
1349
- │ │ │ 8b. Return to payer │
1350
- │ │ │ ─────────────────────>
1351
- └ └ └ └
1352
- ```
1353
-
1354
- ### Basic Escrow Usage
1355
-
1356
- ```typescript
1357
- import {
1358
- EscrowClient,
1359
- canReleaseEscrow,
1360
- canRefundEscrow,
1361
- isEscrowExpired,
1362
- } from 'uvd-x402-sdk/backend';
1363
-
1364
- const escrow = new EscrowClient({
1365
- apiKey: process.env.ESCROW_API_KEY,
1366
- });
1367
-
1368
- // Create escrow payment
1369
- const escrowPayment = await escrow.createEscrow({
1370
- paymentHeader: req.headers['x-payment'],
1371
- requirements: paymentRequirements,
1372
- escrowDuration: 86400, // 24 hours
1373
- releaseConditions: {
1374
- minHoldTime: 3600, // Minimum 1 hour before release
1375
- },
1376
- });
1377
-
1378
- console.log('Escrow ID:', escrowPayment.id);
1379
- console.log('Status:', escrowPayment.status); // 'held'
1380
-
1381
- // Check if we can release
1382
- if (canReleaseEscrow(escrowPayment)) {
1383
- // After service is provided, release funds to recipient
1384
- const released = await escrow.release(escrowPayment.id);
1385
- console.log('Released, tx:', released.transactionHash);
1386
- }
1387
- ```
1388
-
1389
- ### Handling Refunds
1390
-
1391
- ```typescript
1392
- // Payer requests refund
1393
- const refundRequest = await escrow.requestRefund({
1394
- escrowId: escrowPayment.id,
1395
- reason: 'Service not delivered within expected timeframe',
1396
- evidence: 'Order #12345 shows pending status after 48 hours',
1397
- });
1398
-
1399
- // Recipient can approve or reject
1400
- await escrow.approveRefund(refundRequest.id, refundRequest.amountRequested);
1401
- // or
1402
- await escrow.rejectRefund(refundRequest.id, 'Service was delivered, see tracking #XYZ');
1403
- ```
1404
-
1405
- ### Dispute Resolution
1406
-
1407
- ```typescript
1408
- // If parties disagree, open a dispute
1409
- const dispute = await escrow.openDispute(
1410
- escrowPayment.id,
1411
- 'Service quality does not match description',
1412
- 'Screenshots showing issues with delivered product'
1413
- );
1414
-
1415
- // Submit additional evidence
1416
- await escrow.submitEvidence(dispute.id, 'Additional documentation...');
1417
-
1418
- // Check dispute status
1419
- const updatedDispute = await escrow.getDispute(dispute.id);
1420
- console.log('Outcome:', updatedDispute.outcome);
1421
- // 'pending' | 'payer_wins' | 'recipient_wins' | 'split'
1422
- ```
1423
-
1424
- ### Helper Functions
1425
-
1426
- ```typescript
1427
- import {
1428
- canReleaseEscrow,
1429
- canRefundEscrow,
1430
- isEscrowExpired,
1431
- escrowTimeRemaining,
1432
- } from 'uvd-x402-sdk/backend';
1433
-
1434
- // Check if escrow can be released
1435
- if (canReleaseEscrow(escrowPayment)) {
1436
- await escrow.release(escrowPayment.id);
1437
- }
1438
-
1439
- // Check if escrow can be refunded
1440
- if (canRefundEscrow(escrowPayment)) {
1441
- await escrow.requestRefund({ escrowId: escrowPayment.id, reason: '...' });
1442
- }
1443
-
1444
- // Check expiration
1445
- if (isEscrowExpired(escrowPayment)) {
1446
- console.log('Escrow has expired');
1447
- }
1448
-
1449
- // Time remaining
1450
- const msRemaining = escrowTimeRemaining(escrowPayment);
1451
- console.log(`Expires in ${msRemaining / 1000 / 60} minutes`);
1452
- ```
1453
-
1454
- ---
1455
-
1456
- ## Troubleshooting
1457
-
1458
- ### Common Issues
1459
-
1460
- #### "No Ethereum wallet found"
1461
-
1462
- Install MetaMask or another EVM wallet. For mobile, use WalletConnect.
1463
-
1464
- #### "Phantom wallet not installed"
1465
-
1466
- Install Phantom from [phantom.app](https://phantom.app) for Solana/Fogo support.
1467
-
1468
- #### "Freighter wallet not installed"
1469
-
1470
- Install Freighter from [freighter.app](https://www.freighter.app) for Stellar support.
1471
-
1472
- #### "No NEAR wallet found"
1473
-
1474
- Install MyNearWallet or Meteor wallet for NEAR support.
1475
-
1476
- #### "Chain not supported"
1477
-
1478
- Check if the chain is enabled in `SUPPORTED_CHAINS`.
1479
-
1480
- #### "Signature rejected by user"
1481
-
1482
- User clicked "Reject" in their wallet. This is not an error - just user cancellation.
1483
-
1484
- #### Wrong network in X-PAYMENT header
1485
-
1486
- For SVM chains, always pass `chainConfig` to `encodePaymentHeader()`:
1487
-
1488
- ```typescript
1489
- // WRONG - will use 'solana' for Fogo
1490
- const header = svm.encodePaymentHeader(payload);
1491
-
1492
- // CORRECT - uses 'fogo' for Fogo
1493
- const fogoConfig = getChainByName('fogo')!;
1494
- const header = svm.encodePaymentHeader(payload, fogoConfig);
1495
- ```
1496
-
1497
- ### Debug Mode
1498
-
1499
- Enable debug logging:
1500
-
1501
- ```typescript
1502
- const client = new X402Client({
1503
- debug: true,
1504
- defaultChain: 'base',
1505
- });
1506
- ```
1507
-
1508
- ---
1509
-
1510
- ## Security
1511
-
1512
- - Users NEVER pay gas or submit transactions directly
1513
- - EVM: Users sign EIP-712 structured messages only
1514
- - Solana/Fogo: Users sign partial transactions (USDC transfer instruction only)
1515
- - Stellar: Users sign Soroban authorization entries only
1516
- - NEAR: Users sign NEP-366 meta-transactions only
1517
- - The facilitator submits and pays for all transactions
1518
-
1519
- ---
1520
-
1521
- ## License
1522
-
1523
- MIT License - see [LICENSE](LICENSE) for details.
1524
-
1525
- ---
1526
-
1527
- ## Links
1528
-
1529
- - [x402 Protocol](https://x402.org)
1530
- - [Ultravioleta DAO](https://ultravioletadao.xyz)
1531
- - [402milly](https://402milly.xyz)
1532
- - [GitHub](https://github.com/UltravioletaDAO/uvd-x402-sdk-typescript)
1533
- - [npm](https://www.npmjs.com/package/uvd-x402-sdk)
355
+ MIT