uvd-x402-sdk 2.6.0 → 2.10.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 (71) hide show
  1. package/README.md +380 -3
  2. package/dist/adapters/index.d.mts +1 -1
  3. package/dist/adapters/index.d.ts +1 -1
  4. package/dist/adapters/index.js +78 -1
  5. package/dist/adapters/index.js.map +1 -1
  6. package/dist/adapters/index.mjs +78 -1
  7. package/dist/adapters/index.mjs.map +1 -1
  8. package/dist/backend/index.d.mts +1036 -0
  9. package/dist/backend/index.d.ts +1036 -0
  10. package/dist/backend/index.js +1722 -0
  11. package/dist/backend/index.js.map +1 -0
  12. package/dist/backend/index.mjs +1704 -0
  13. package/dist/backend/index.mjs.map +1 -0
  14. package/dist/{index-fwbSkart.d.ts → index-C60c_e5z.d.mts} +13 -4
  15. package/dist/{index-BR1o8JZQ.d.mts → index-D-dO_FoP.d.mts} +38 -4
  16. package/dist/{index-BR1o8JZQ.d.ts → index-D-dO_FoP.d.ts} +38 -4
  17. package/dist/{index-DKbWiaJ9.d.mts → index-VIOUicmO.d.ts} +13 -4
  18. package/dist/index.d.mts +2 -2
  19. package/dist/index.d.ts +2 -2
  20. package/dist/index.js +93 -1
  21. package/dist/index.js.map +1 -1
  22. package/dist/index.mjs +92 -2
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/providers/algorand/index.d.mts +86 -0
  25. package/dist/providers/algorand/index.d.ts +86 -0
  26. package/dist/providers/algorand/index.js +903 -0
  27. package/dist/providers/algorand/index.js.map +1 -0
  28. package/dist/providers/algorand/index.mjs +898 -0
  29. package/dist/providers/algorand/index.mjs.map +1 -0
  30. package/dist/providers/evm/index.d.mts +1 -1
  31. package/dist/providers/evm/index.d.ts +1 -1
  32. package/dist/providers/evm/index.js +78 -1
  33. package/dist/providers/evm/index.js.map +1 -1
  34. package/dist/providers/evm/index.mjs +78 -1
  35. package/dist/providers/evm/index.mjs.map +1 -1
  36. package/dist/providers/near/index.d.mts +1 -1
  37. package/dist/providers/near/index.d.ts +1 -1
  38. package/dist/providers/near/index.js +78 -1
  39. package/dist/providers/near/index.js.map +1 -1
  40. package/dist/providers/near/index.mjs +78 -1
  41. package/dist/providers/near/index.mjs.map +1 -1
  42. package/dist/providers/solana/index.d.mts +1 -1
  43. package/dist/providers/solana/index.d.ts +1 -1
  44. package/dist/providers/solana/index.js +78 -1
  45. package/dist/providers/solana/index.js.map +1 -1
  46. package/dist/providers/solana/index.mjs +78 -1
  47. package/dist/providers/solana/index.mjs.map +1 -1
  48. package/dist/providers/stellar/index.d.mts +1 -1
  49. package/dist/providers/stellar/index.d.ts +1 -1
  50. package/dist/providers/stellar/index.js +78 -1
  51. package/dist/providers/stellar/index.js.map +1 -1
  52. package/dist/providers/stellar/index.mjs +78 -1
  53. package/dist/providers/stellar/index.mjs.map +1 -1
  54. package/dist/react/index.d.mts +3 -3
  55. package/dist/react/index.d.ts +3 -3
  56. package/dist/react/index.js +78 -1
  57. package/dist/react/index.js.map +1 -1
  58. package/dist/react/index.mjs +78 -1
  59. package/dist/react/index.mjs.map +1 -1
  60. package/dist/utils/index.d.mts +1 -1
  61. package/dist/utils/index.d.ts +1 -1
  62. package/dist/utils/index.js +78 -1
  63. package/dist/utils/index.js.map +1 -1
  64. package/dist/utils/index.mjs +78 -1
  65. package/dist/utils/index.mjs.map +1 -1
  66. package/package.json +24 -3
  67. package/src/backend/index.ts +2131 -0
  68. package/src/chains/index.ts +94 -2
  69. package/src/index.ts +19 -1
  70. package/src/providers/algorand/index.ts +356 -0
  71. package/src/types/index.ts +44 -3
@@ -1,11 +1,12 @@
1
1
  /**
2
2
  * uvd-x402-sdk - Chain Registry
3
3
  *
4
- * Complete configuration for all 15 supported blockchain networks.
5
- * EVM chains (11): Use ERC-3009 TransferWithAuthorization
4
+ * Complete configuration for all 16 supported blockchain networks.
5
+ * EVM chains (10): Use ERC-3009 TransferWithAuthorization
6
6
  * SVM chains (2): Solana and Fogo - Use SPL tokens with partially-signed transactions
7
7
  * Stellar (1): Uses Soroban authorization entries
8
8
  * NEAR (1): Uses NEP-366 meta-transactions
9
+ * Algorand (2): Uses ASA transfers with atomic transaction groups
9
10
  */
10
11
 
11
12
  import type { ChainConfig, NetworkType, TokenType, TokenConfig } from '../types';
@@ -541,6 +542,76 @@ export const SUPPORTED_CHAINS: Record<string, ChainConfig> = {
541
542
  enabled: true, // NEP-366 meta-transactions supported
542
543
  },
543
544
  },
545
+
546
+ // ============================================================================
547
+ // ALGORAND (2 networks) - Uses ASA transfers with atomic transaction groups
548
+ // ============================================================================
549
+
550
+ algorand: {
551
+ chainId: 0, // Non-EVM (Algorand uses genesis hash for network identification)
552
+ chainIdHex: '0x0',
553
+ name: 'algorand',
554
+ displayName: 'Algorand',
555
+ networkType: 'algorand',
556
+ rpcUrl: 'https://mainnet-api.algonode.cloud',
557
+ explorerUrl: 'https://allo.info',
558
+ nativeCurrency: {
559
+ name: 'Algo',
560
+ symbol: 'ALGO',
561
+ decimals: 6, // Algorand uses 6 decimals (microAlgos)
562
+ },
563
+ usdc: {
564
+ address: '31566704', // USDC ASA ID on Algorand mainnet
565
+ decimals: 6,
566
+ name: 'USDC',
567
+ version: '1',
568
+ },
569
+ tokens: {
570
+ usdc: {
571
+ address: '31566704', // USDC ASA ID on Algorand mainnet
572
+ decimals: 6,
573
+ name: 'USDC',
574
+ version: '1',
575
+ },
576
+ },
577
+ x402: {
578
+ facilitatorUrl: DEFAULT_FACILITATOR_URL,
579
+ enabled: true,
580
+ },
581
+ },
582
+
583
+ 'algorand-testnet': {
584
+ chainId: 0, // Non-EVM
585
+ chainIdHex: '0x0',
586
+ name: 'algorand-testnet',
587
+ displayName: 'Algorand Testnet',
588
+ networkType: 'algorand',
589
+ rpcUrl: 'https://testnet-api.algonode.cloud',
590
+ explorerUrl: 'https://testnet.allo.info',
591
+ nativeCurrency: {
592
+ name: 'Algo',
593
+ symbol: 'ALGO',
594
+ decimals: 6,
595
+ },
596
+ usdc: {
597
+ address: '10458941', // USDC ASA ID on Algorand testnet
598
+ decimals: 6,
599
+ name: 'USDC',
600
+ version: '1',
601
+ },
602
+ tokens: {
603
+ usdc: {
604
+ address: '10458941', // USDC ASA ID on Algorand testnet
605
+ decimals: 6,
606
+ name: 'USDC',
607
+ version: '1',
608
+ },
609
+ },
610
+ x402: {
611
+ facilitatorUrl: DEFAULT_FACILITATOR_URL,
612
+ enabled: true,
613
+ },
614
+ },
544
615
  };
545
616
 
546
617
  /**
@@ -637,6 +708,8 @@ export function getExplorerTxUrl(chainName: string, txHash: string): string | nu
637
708
  return `${chain.explorerUrl}/tx/${txHash}`;
638
709
  case 'near':
639
710
  return `${chain.explorerUrl}/txns/${txHash}`;
711
+ case 'algorand':
712
+ return `${chain.explorerUrl}/tx/${txHash}`;
640
713
  default:
641
714
  return null;
642
715
  }
@@ -659,11 +732,30 @@ export function getExplorerAddressUrl(chainName: string, address: string): strin
659
732
  return `${chain.explorerUrl}/account/${address}`;
660
733
  case 'near':
661
734
  return `${chain.explorerUrl}/address/${address}`;
735
+ case 'algorand':
736
+ return `${chain.explorerUrl}/account/${address}`;
662
737
  default:
663
738
  return null;
664
739
  }
665
740
  }
666
741
 
742
+ /**
743
+ * Get list of Algorand chains
744
+ */
745
+ export function getAlgorandChains(): ChainConfig[] {
746
+ return Object.values(SUPPORTED_CHAINS).filter(
747
+ chain => chain.networkType === 'algorand' && chain.x402.enabled
748
+ );
749
+ }
750
+
751
+ /**
752
+ * Check if a chain is Algorand-based
753
+ */
754
+ export function isAlgorandChain(chainName: string): boolean {
755
+ const chain = getChainByName(chainName);
756
+ return chain?.networkType === 'algorand';
757
+ }
758
+
667
759
  // ============================================================================
668
760
  // MULTI-TOKEN SUPPORT FUNCTIONS
669
761
  // ============================================================================
package/src/index.ts CHANGED
@@ -3,11 +3,12 @@
3
3
  *
4
4
  * x402 Payment SDK - Gasless crypto payments using the Ultravioleta facilitator.
5
5
  *
6
- * Supports 14 blockchain networks:
6
+ * Supports 16 blockchain networks:
7
7
  * - EVM (10): Base, Ethereum, Polygon, Arbitrum, Optimism, Avalanche, Celo, HyperEVM, Unichain, Monad
8
8
  * - SVM (2): Solana, Fogo
9
9
  * - Stellar (1): Stellar
10
10
  * - NEAR (1): NEAR Protocol
11
+ * - Algorand (2): Algorand mainnet and testnet
11
12
  *
12
13
  * Supports both x402 v1 and v2 protocols.
13
14
  *
@@ -60,6 +61,18 @@
60
61
  * const header = near.encodePaymentHeader(payload);
61
62
  * ```
62
63
  *
64
+ * @example With Algorand
65
+ * ```ts
66
+ * import { AlgorandProvider } from 'uvd-x402-sdk/algorand';
67
+ * import { getChainByName } from 'uvd-x402-sdk';
68
+ *
69
+ * const algorand = new AlgorandProvider();
70
+ * const address = await algorand.connect();
71
+ * const algorandConfig = getChainByName('algorand')!;
72
+ * const payload = await algorand.signPayment(paymentInfo, algorandConfig);
73
+ * const header = algorand.encodePaymentHeader(payload, algorandConfig);
74
+ * ```
75
+ *
63
76
  * @example With React
64
77
  * ```tsx
65
78
  * import { X402Provider, useX402, usePayment } from 'uvd-x402-sdk/react';
@@ -100,6 +113,9 @@ export {
100
113
  getSupportedTokens,
101
114
  isTokenSupported,
102
115
  getChainsByToken,
116
+ // Algorand helper functions
117
+ getAlgorandChains,
118
+ isAlgorandChain,
103
119
  } from './chains';
104
120
 
105
121
  // x402 utilities
@@ -154,6 +170,7 @@ export type {
154
170
  SolanaPaymentPayload,
155
171
  StellarPaymentPayload,
156
172
  NEARPaymentPayload,
173
+ AlgorandPaymentPayload,
157
174
  X402HeaderName,
158
175
 
159
176
  // x402 header types (v1 and v2)
@@ -167,6 +184,7 @@ export type {
167
184
  X402SolanaPayload,
168
185
  X402StellarPayload,
169
186
  X402NEARPayload,
187
+ X402AlgorandPayload,
170
188
 
171
189
  // Config types
172
190
  X402ClientConfig,
@@ -0,0 +1,356 @@
1
+ /**
2
+ * uvd-x402-sdk - Algorand Provider
3
+ *
4
+ * Provides wallet connection and payment creation for Algorand via Pera Wallet.
5
+ * Uses ASA (Algorand Standard Assets) transfers for USDC payments.
6
+ *
7
+ * USDC ASA IDs:
8
+ * - Mainnet: 31566704
9
+ * - Testnet: 10458941
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { AlgorandProvider } from 'uvd-x402-sdk/algorand';
14
+ * import { getChainByName } from 'uvd-x402-sdk';
15
+ *
16
+ * const algorand = new AlgorandProvider();
17
+ *
18
+ * // Connect to Pera Wallet
19
+ * const address = await algorand.connect();
20
+ *
21
+ * // Create Algorand payment
22
+ * const chainConfig = getChainByName('algorand')!;
23
+ * const paymentPayload = await algorand.signPayment(paymentInfo, chainConfig);
24
+ * const header = algorand.encodePaymentHeader(paymentPayload, chainConfig);
25
+ * ```
26
+ */
27
+
28
+ import type {
29
+ ChainConfig,
30
+ PaymentInfo,
31
+ AlgorandPaymentPayload,
32
+ WalletAdapter,
33
+ X402Version,
34
+ } from '../../types';
35
+ import { X402Error } from '../../types';
36
+ import { getChainByName } from '../../chains';
37
+ import { chainToCAIP2 } from '../../utils';
38
+
39
+ /**
40
+ * Browser-compatible base64 encoding for Uint8Array
41
+ */
42
+ function uint8ArrayToBase64(bytes: Uint8Array): string {
43
+ let binary = '';
44
+ for (let i = 0; i < bytes.length; i++) {
45
+ binary += String.fromCharCode(bytes[i]);
46
+ }
47
+ return btoa(binary);
48
+ }
49
+
50
+ // Lazy import Algorand dependencies
51
+ let algosdk: typeof import('algosdk') | null = null;
52
+ let PeraWalletConnect: typeof import('@perawallet/connect').PeraWalletConnect | null = null;
53
+
54
+ async function loadAlgorandDeps() {
55
+ if (!algosdk) {
56
+ algosdk = await import('algosdk');
57
+ }
58
+ if (!PeraWalletConnect) {
59
+ const peraModule = await import('@perawallet/connect');
60
+ PeraWalletConnect = peraModule.PeraWalletConnect;
61
+ }
62
+ }
63
+
64
+ /**
65
+ * AlgorandProvider - Wallet adapter for Algorand via Pera Wallet
66
+ *
67
+ * Supports both mainnet and testnet through chain configuration.
68
+ */
69
+ export class AlgorandProvider implements WalletAdapter {
70
+ readonly id = 'pera';
71
+ readonly name = 'Pera Wallet';
72
+ readonly networkType = 'algorand' as const;
73
+
74
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
75
+ private peraWallet: any = null;
76
+ private address: string | null = null;
77
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
78
+ private algodClients: Map<string, any> = new Map();
79
+
80
+ /**
81
+ * Check if Pera Wallet is available
82
+ * Note: Pera works as a WalletConnect modal, so it's always "available"
83
+ */
84
+ isAvailable(): boolean {
85
+ return typeof window !== 'undefined';
86
+ }
87
+
88
+ /**
89
+ * Connect to Pera Wallet
90
+ */
91
+ async connect(_chainName?: string): Promise<string> {
92
+ await loadAlgorandDeps();
93
+
94
+ if (!PeraWalletConnect) {
95
+ throw new X402Error('Failed to load Pera Wallet SDK', 'WALLET_NOT_FOUND');
96
+ }
97
+
98
+ try {
99
+ // Create Pera Wallet instance
100
+ this.peraWallet = new PeraWalletConnect!();
101
+
102
+ // Try to reconnect from previous session
103
+ const accounts = await this.peraWallet.reconnectSession();
104
+
105
+ if (accounts.length > 0) {
106
+ this.address = accounts[0];
107
+ return accounts[0];
108
+ }
109
+
110
+ // If no previous session, connect fresh
111
+ const newAccounts = await this.peraWallet.connect();
112
+
113
+ if (newAccounts.length === 0) {
114
+ throw new X402Error('No accounts returned from Pera Wallet', 'WALLET_CONNECTION_REJECTED');
115
+ }
116
+
117
+ this.address = newAccounts[0];
118
+
119
+ // Set up disconnect handler
120
+ this.peraWallet.connector?.on('disconnect', () => {
121
+ this.address = null;
122
+ });
123
+
124
+ return newAccounts[0];
125
+ } catch (error: unknown) {
126
+ if (error instanceof Error) {
127
+ if (error.message.includes('rejected') || error.message.includes('cancelled')) {
128
+ throw new X402Error('Connection rejected by user', 'WALLET_CONNECTION_REJECTED');
129
+ }
130
+ }
131
+ throw new X402Error(
132
+ `Failed to connect Pera Wallet: ${error instanceof Error ? error.message : 'Unknown error'}`,
133
+ 'UNKNOWN_ERROR',
134
+ error
135
+ );
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Disconnect from Pera Wallet
141
+ */
142
+ async disconnect(): Promise<void> {
143
+ if (this.peraWallet) {
144
+ try {
145
+ await this.peraWallet.disconnect();
146
+ } catch {
147
+ // Ignore disconnect errors
148
+ }
149
+ }
150
+ this.peraWallet = null;
151
+ this.address = null;
152
+ this.algodClients.clear();
153
+ }
154
+
155
+ /**
156
+ * Get current address
157
+ */
158
+ getAddress(): string | null {
159
+ return this.address;
160
+ }
161
+
162
+ /**
163
+ * Get USDC (ASA) balance
164
+ */
165
+ async getBalance(chainConfig: ChainConfig): Promise<string> {
166
+ await loadAlgorandDeps();
167
+
168
+ if (!this.address) {
169
+ throw new X402Error('Wallet not connected', 'WALLET_NOT_CONNECTED');
170
+ }
171
+
172
+ const algodClient = await this.getAlgodClient(chainConfig);
173
+ const assetId = parseInt(chainConfig.usdc.address, 10);
174
+
175
+ try {
176
+ const accountInfo = await algodClient.accountInformation(this.address).do();
177
+
178
+ // Find the USDC asset in the account's assets
179
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
180
+ const assets: any[] = accountInfo.assets || accountInfo['assets'] || [];
181
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
182
+ const usdcAsset = assets.find((asset: any) =>
183
+ (asset.assetId || asset['asset-id']) === assetId
184
+ );
185
+
186
+ if (!usdcAsset) {
187
+ return '0.00'; // Account not opted into USDC
188
+ }
189
+
190
+ const amount = Number(usdcAsset.amount || usdcAsset['amount']);
191
+ const balance = amount / Math.pow(10, chainConfig.usdc.decimals);
192
+ return balance.toFixed(2);
193
+ } catch {
194
+ return '0.00';
195
+ }
196
+ }
197
+
198
+ /**
199
+ * Create Algorand ASA transfer payment
200
+ *
201
+ * Transaction structure:
202
+ * 1. ASA Transfer from user to recipient
203
+ * 2. Facilitator pays transaction fees
204
+ */
205
+ async signPayment(paymentInfo: PaymentInfo, chainConfig: ChainConfig): Promise<string> {
206
+ await loadAlgorandDeps();
207
+
208
+ if (!this.peraWallet || !this.address) {
209
+ throw new X402Error('Wallet not connected', 'WALLET_NOT_CONNECTED');
210
+ }
211
+
212
+ if (!algosdk) {
213
+ throw new X402Error('Algorand SDK not loaded', 'UNKNOWN_ERROR');
214
+ }
215
+
216
+ const algodClient = await this.getAlgodClient(chainConfig);
217
+
218
+ // Get recipient address (use algorand-specific or fallback to default)
219
+ const recipient = paymentInfo.recipients?.algorand || paymentInfo.recipient;
220
+ const assetId = parseInt(chainConfig.usdc.address, 10);
221
+
222
+ // Parse amount (6 decimals for USDC)
223
+ const amount = Math.floor(parseFloat(paymentInfo.amount) * 1_000_000);
224
+
225
+ try {
226
+ // Get suggested transaction parameters
227
+ const suggestedParams = await algodClient.getTransactionParams().do();
228
+
229
+ // Create ASA transfer transaction
230
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
231
+ const txn = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({
232
+ sender: this.address,
233
+ receiver: recipient,
234
+ amount: BigInt(amount),
235
+ assetIndex: assetId,
236
+ suggestedParams: suggestedParams,
237
+ note: new TextEncoder().encode('x402 payment via uvd-x402-sdk'),
238
+ } as any);
239
+
240
+ // Sign with Pera Wallet
241
+ const signedTxns = await this.peraWallet.signTransaction([[{ txn }]]);
242
+
243
+ if (!signedTxns || signedTxns.length === 0) {
244
+ throw new X402Error('No signed transaction returned', 'SIGNATURE_REJECTED');
245
+ }
246
+
247
+ const signedTxn = signedTxns[0];
248
+
249
+ const payload: AlgorandPaymentPayload = {
250
+ from: this.address,
251
+ to: recipient,
252
+ amount: amount.toString(),
253
+ assetId: assetId,
254
+ signedTxn: uint8ArrayToBase64(signedTxn),
255
+ };
256
+
257
+ return JSON.stringify(payload);
258
+ } catch (error: unknown) {
259
+ if (error instanceof X402Error) {
260
+ throw error;
261
+ }
262
+ if (error instanceof Error) {
263
+ if (error.message.includes('rejected') || error.message.includes('cancelled')) {
264
+ throw new X402Error('Signature rejected by user', 'SIGNATURE_REJECTED');
265
+ }
266
+ }
267
+ throw new X402Error(
268
+ `Failed to sign transaction: ${error instanceof Error ? error.message : 'Unknown error'}`,
269
+ 'PAYMENT_FAILED',
270
+ error
271
+ );
272
+ }
273
+ }
274
+
275
+ /**
276
+ * Encode Algorand payment as X-PAYMENT header
277
+ *
278
+ * @param paymentPayload - JSON-encoded payment payload from signPayment()
279
+ * @param chainConfig - Chain configuration
280
+ * @param version - x402 protocol version (1 or 2, defaults to 1)
281
+ * @returns Base64-encoded X-PAYMENT header value
282
+ */
283
+ encodePaymentHeader(
284
+ paymentPayload: string,
285
+ chainConfig?: ChainConfig,
286
+ version: X402Version = 1
287
+ ): string {
288
+ const payload = JSON.parse(paymentPayload) as AlgorandPaymentPayload;
289
+
290
+ // Use chain name from config, or default to 'algorand'
291
+ const networkName = chainConfig?.name || 'algorand';
292
+
293
+ // Build the payload data
294
+ const payloadData = {
295
+ from: payload.from,
296
+ to: payload.to,
297
+ amount: payload.amount,
298
+ assetId: payload.assetId,
299
+ signedTxn: payload.signedTxn,
300
+ ...(payload.note && { note: payload.note }),
301
+ };
302
+
303
+ // Format in x402 standard format (v1 or v2)
304
+ const x402Payload = version === 2
305
+ ? {
306
+ x402Version: 2 as const,
307
+ scheme: 'exact' as const,
308
+ network: chainToCAIP2(networkName), // CAIP-2 format for v2
309
+ payload: payloadData,
310
+ }
311
+ : {
312
+ x402Version: 1 as const,
313
+ scheme: 'exact' as const,
314
+ network: networkName, // Plain chain name for v1
315
+ payload: payloadData,
316
+ };
317
+
318
+ return btoa(JSON.stringify(x402Payload));
319
+ }
320
+
321
+ // Private helpers
322
+
323
+ /**
324
+ * Get or create an Algod client for a specific chain
325
+ */
326
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
327
+ private async getAlgodClient(chainConfig?: ChainConfig): Promise<any> {
328
+ await loadAlgorandDeps();
329
+
330
+ if (!algosdk) {
331
+ throw new X402Error('Algorand SDK not loaded', 'UNKNOWN_ERROR');
332
+ }
333
+
334
+ const config = chainConfig || getChainByName('algorand');
335
+ if (!config) {
336
+ throw new X402Error('Chain config not found', 'CHAIN_NOT_SUPPORTED');
337
+ }
338
+
339
+ // Cache by RPC URL
340
+ const cacheKey = config.rpcUrl;
341
+
342
+ if (this.algodClients.has(cacheKey)) {
343
+ return this.algodClients.get(cacheKey)!;
344
+ }
345
+
346
+ // Create new Algod client
347
+ // Algonode.cloud doesn't require auth token
348
+ const client = new algosdk.Algodv2('', config.rpcUrl, '');
349
+ this.algodClients.set(cacheKey, client);
350
+
351
+ return client;
352
+ }
353
+ }
354
+
355
+ // Default export
356
+ export default AlgorandProvider;
@@ -15,10 +15,11 @@
15
15
  * - 'svm': Solana Virtual Machine chains (Solana, Fogo) (use SPL tokens)
16
16
  * - 'stellar': Stellar network (use Soroban)
17
17
  * - 'near': NEAR Protocol (use NEP-366)
18
+ * - 'algorand': Algorand network (use ASA transfers with atomic transactions)
18
19
  *
19
20
  * @deprecated 'solana' type is deprecated, use 'svm' instead
20
21
  */
21
- export type NetworkType = 'evm' | 'svm' | 'solana' | 'stellar' | 'near';
22
+ export type NetworkType = 'evm' | 'svm' | 'solana' | 'stellar' | 'near' | 'algorand';
22
23
 
23
24
  /**
24
25
  * Supported stablecoin token types
@@ -200,6 +201,7 @@ export interface PaymentInfo {
200
201
  solana?: string;
201
202
  near?: string;
202
203
  stellar?: string;
204
+ algorand?: string;
203
205
  };
204
206
  /** Facilitator address (for Solana fee payer) */
205
207
  facilitator?: string;
@@ -340,6 +342,28 @@ export interface NEARPaymentPayload {
340
342
  network: 'near';
341
343
  }
342
344
 
345
+ /**
346
+ * Algorand payment payload (atomic transaction group)
347
+ *
348
+ * Algorand uses a unique payment model where the facilitator creates and signs
349
+ * an atomic transaction group. The user signs their portion (the ASA transfer)
350
+ * and the facilitator submits the complete group.
351
+ */
352
+ export interface AlgorandPaymentPayload {
353
+ /** Sender's Algorand address (58-character base32) */
354
+ from: string;
355
+ /** Recipient's Algorand address */
356
+ to: string;
357
+ /** Amount in base units (microAlgos for ALGO, or base units for ASA) */
358
+ amount: string;
359
+ /** USDC ASA ID (31566704 for mainnet, 10458941 for testnet) */
360
+ assetId: number;
361
+ /** Base64-encoded signed transaction bytes */
362
+ signedTxn: string;
363
+ /** Optional note field */
364
+ note?: string;
365
+ }
366
+
343
367
  /**
344
368
  * Union type for all payment payloads
345
369
  */
@@ -347,7 +371,8 @@ export type PaymentPayload =
347
371
  | EVMPaymentPayload
348
372
  | SolanaPaymentPayload
349
373
  | StellarPaymentPayload
350
- | NEARPaymentPayload;
374
+ | NEARPaymentPayload
375
+ | AlgorandPaymentPayload;
351
376
 
352
377
  // ============================================================================
353
378
  // X402 HEADER TYPES (v1 and v2)
@@ -381,6 +406,9 @@ export const CAIP2_IDENTIFIERS: Record<string, string> = {
381
406
  stellar: 'stellar:pubnet',
382
407
  // NEAR
383
408
  near: 'near:mainnet',
409
+ // Algorand
410
+ algorand: 'algorand:mainnet',
411
+ 'algorand-testnet': 'algorand:testnet',
384
412
  };
385
413
 
386
414
  /**
@@ -468,6 +496,18 @@ export interface X402NEARPayload {
468
496
  signedDelegateAction: string;
469
497
  }
470
498
 
499
+ /**
500
+ * Algorand-specific payload in x402 header
501
+ */
502
+ export interface X402AlgorandPayload {
503
+ from: string;
504
+ to: string;
505
+ amount: string;
506
+ assetId: number;
507
+ signedTxn: string;
508
+ note?: string;
509
+ }
510
+
471
511
  /**
472
512
  * Union of all x402 payload types
473
513
  */
@@ -475,7 +515,8 @@ export type X402PayloadData =
475
515
  | X402EVMPayload
476
516
  | X402SolanaPayload
477
517
  | X402StellarPayload
478
- | X402NEARPayload;
518
+ | X402NEARPayload
519
+ | X402AlgorandPayload;
479
520
 
480
521
  // ============================================================================
481
522
  // CLIENT CONFIGURATION