uvd-x402-sdk 2.10.0 → 2.11.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.
- package/dist/adapters/index.js +16 -0
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/index.mjs +16 -0
- package/dist/adapters/index.mjs.map +1 -1
- package/dist/backend/index.js +16 -0
- package/dist/backend/index.js.map +1 -1
- package/dist/backend/index.mjs +16 -0
- package/dist/backend/index.mjs.map +1 -1
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +16 -0
- package/dist/index.mjs.map +1 -1
- package/dist/providers/algorand/index.d.mts +31 -10
- package/dist/providers/algorand/index.d.ts +31 -10
- package/dist/providers/algorand/index.js +125 -13
- package/dist/providers/algorand/index.js.map +1 -1
- package/dist/providers/algorand/index.mjs +125 -13
- package/dist/providers/algorand/index.mjs.map +1 -1
- package/dist/providers/evm/index.js +16 -0
- package/dist/providers/evm/index.js.map +1 -1
- package/dist/providers/evm/index.mjs +16 -0
- package/dist/providers/evm/index.mjs.map +1 -1
- package/dist/providers/near/index.js +16 -0
- package/dist/providers/near/index.js.map +1 -1
- package/dist/providers/near/index.mjs +16 -0
- package/dist/providers/near/index.mjs.map +1 -1
- package/dist/providers/solana/index.js +16 -0
- package/dist/providers/solana/index.js.map +1 -1
- package/dist/providers/solana/index.mjs +16 -0
- package/dist/providers/solana/index.mjs.map +1 -1
- package/dist/providers/stellar/index.js +16 -0
- package/dist/providers/stellar/index.js.map +1 -1
- package/dist/providers/stellar/index.mjs +16 -0
- package/dist/providers/stellar/index.mjs.map +1 -1
- package/dist/react/index.js +16 -0
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +16 -0
- package/dist/react/index.mjs.map +1 -1
- package/dist/utils/index.js +16 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/index.mjs +16 -0
- package/dist/utils/index.mjs.map +1 -1
- package/package.json +6 -1
- package/src/chains/index.ts +14 -0
- package/src/providers/algorand/index.ts +155 -19
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* uvd-x402-sdk - Algorand Provider
|
|
3
3
|
*
|
|
4
|
-
* Provides wallet connection and payment creation for Algorand
|
|
4
|
+
* Provides wallet connection and payment creation for Algorand.
|
|
5
|
+
* Supports both Lute Wallet (desktop browser extension) and Pera Wallet (mobile).
|
|
5
6
|
* Uses ASA (Algorand Standard Assets) transfers for USDC payments.
|
|
6
7
|
*
|
|
8
|
+
* Wallet Priority:
|
|
9
|
+
* 1. Lute Wallet - Desktop browser extension (preferred for desktop)
|
|
10
|
+
* 2. Pera Wallet - Mobile via WalletConnect (fallback/mobile)
|
|
11
|
+
*
|
|
7
12
|
* USDC ASA IDs:
|
|
8
13
|
* - Mainnet: 31566704
|
|
9
14
|
* - Testnet: 10458941
|
|
@@ -15,7 +20,7 @@
|
|
|
15
20
|
*
|
|
16
21
|
* const algorand = new AlgorandProvider();
|
|
17
22
|
*
|
|
18
|
-
* // Connect to Pera
|
|
23
|
+
* // Connect to Lute (desktop) or Pera (mobile) automatically
|
|
19
24
|
* const address = await algorand.connect();
|
|
20
25
|
*
|
|
21
26
|
* // Create Algorand payment
|
|
@@ -50,27 +55,60 @@ function uint8ArrayToBase64(bytes: Uint8Array): string {
|
|
|
50
55
|
// Lazy import Algorand dependencies
|
|
51
56
|
let algosdk: typeof import('algosdk') | null = null;
|
|
52
57
|
let PeraWalletConnect: typeof import('@perawallet/connect').PeraWalletConnect | null = null;
|
|
58
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
59
|
+
let LuteConnect: any = null;
|
|
53
60
|
|
|
54
61
|
async function loadAlgorandDeps() {
|
|
55
62
|
if (!algosdk) {
|
|
56
63
|
algosdk = await import('algosdk');
|
|
57
64
|
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function loadPeraWallet() {
|
|
58
68
|
if (!PeraWalletConnect) {
|
|
59
69
|
const peraModule = await import('@perawallet/connect');
|
|
60
70
|
PeraWalletConnect = peraModule.PeraWalletConnect;
|
|
61
71
|
}
|
|
62
72
|
}
|
|
63
73
|
|
|
74
|
+
async function loadLuteWallet() {
|
|
75
|
+
if (!LuteConnect) {
|
|
76
|
+
try {
|
|
77
|
+
const luteModule = await import('lute-connect');
|
|
78
|
+
LuteConnect = luteModule.default;
|
|
79
|
+
} catch {
|
|
80
|
+
// Lute not installed, will fall back to Pera
|
|
81
|
+
LuteConnect = null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Check if Lute wallet extension is installed
|
|
88
|
+
*/
|
|
89
|
+
function isLuteAvailable(): boolean {
|
|
90
|
+
if (typeof window === 'undefined') return false;
|
|
91
|
+
// Lute injects itself into window.algorand or window.lute
|
|
92
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
93
|
+
const win = window as any;
|
|
94
|
+
return !!(win.algorand || win.lute);
|
|
95
|
+
}
|
|
96
|
+
|
|
64
97
|
/**
|
|
65
|
-
* AlgorandProvider - Wallet adapter for Algorand
|
|
98
|
+
* AlgorandProvider - Wallet adapter for Algorand
|
|
66
99
|
*
|
|
67
|
-
* Supports
|
|
100
|
+
* Supports Lute Wallet (desktop) and Pera Wallet (mobile).
|
|
101
|
+
* Automatically detects and uses the best available wallet.
|
|
68
102
|
*/
|
|
69
103
|
export class AlgorandProvider implements WalletAdapter {
|
|
70
|
-
readonly id = '
|
|
71
|
-
readonly name = '
|
|
104
|
+
readonly id = 'algorand';
|
|
105
|
+
readonly name = 'Algorand Wallet';
|
|
72
106
|
readonly networkType = 'algorand' as const;
|
|
73
107
|
|
|
108
|
+
// Active wallet type
|
|
109
|
+
private walletType: 'lute' | 'pera' | null = null;
|
|
110
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
111
|
+
private luteWallet: any = null;
|
|
74
112
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
75
113
|
private peraWallet: any = null;
|
|
76
114
|
private address: string | null = null;
|
|
@@ -78,19 +116,91 @@ export class AlgorandProvider implements WalletAdapter {
|
|
|
78
116
|
private algodClients: Map<string, any> = new Map();
|
|
79
117
|
|
|
80
118
|
/**
|
|
81
|
-
* Check if
|
|
82
|
-
*
|
|
119
|
+
* Check if any Algorand wallet is available
|
|
120
|
+
* Returns true if Lute extension is installed OR we can use Pera (always available via WalletConnect)
|
|
83
121
|
*/
|
|
84
122
|
isAvailable(): boolean {
|
|
85
123
|
return typeof window !== 'undefined';
|
|
86
124
|
}
|
|
87
125
|
|
|
88
126
|
/**
|
|
89
|
-
*
|
|
127
|
+
* Get the name of the currently connected wallet
|
|
128
|
+
*/
|
|
129
|
+
getWalletName(): string {
|
|
130
|
+
if (this.walletType === 'lute') return 'Lute Wallet';
|
|
131
|
+
if (this.walletType === 'pera') return 'Pera Wallet';
|
|
132
|
+
return 'Algorand Wallet';
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Connect to Algorand wallet
|
|
137
|
+
* Priority: Lute (desktop extension) > Pera (mobile via WalletConnect)
|
|
90
138
|
*/
|
|
91
139
|
async connect(_chainName?: string): Promise<string> {
|
|
92
140
|
await loadAlgorandDeps();
|
|
93
141
|
|
|
142
|
+
// Try Lute first (better desktop UX)
|
|
143
|
+
if (isLuteAvailable()) {
|
|
144
|
+
try {
|
|
145
|
+
return await this.connectLute();
|
|
146
|
+
} catch (error) {
|
|
147
|
+
// Lute failed, try Pera
|
|
148
|
+
console.warn('Lute connection failed, falling back to Pera:', error);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Fall back to Pera (mobile/WalletConnect)
|
|
153
|
+
return await this.connectPera();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Connect to Lute Wallet (desktop browser extension)
|
|
158
|
+
*/
|
|
159
|
+
private async connectLute(): Promise<string> {
|
|
160
|
+
await loadLuteWallet();
|
|
161
|
+
|
|
162
|
+
if (!LuteConnect) {
|
|
163
|
+
throw new X402Error('Lute Wallet SDK not available', 'WALLET_NOT_FOUND');
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
try {
|
|
167
|
+
this.luteWallet = new LuteConnect('402milly');
|
|
168
|
+
|
|
169
|
+
// Get Algorand genesis ID for mainnet
|
|
170
|
+
const genesisId = 'mainnet-v1.0';
|
|
171
|
+
|
|
172
|
+
// Connect and get accounts
|
|
173
|
+
const accounts = await this.luteWallet.connect(genesisId);
|
|
174
|
+
|
|
175
|
+
if (!accounts || accounts.length === 0) {
|
|
176
|
+
throw new X402Error('No accounts returned from Lute Wallet', 'WALLET_CONNECTION_REJECTED');
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
this.address = accounts[0];
|
|
180
|
+
this.walletType = 'lute';
|
|
181
|
+
|
|
182
|
+
return accounts[0];
|
|
183
|
+
} catch (error: unknown) {
|
|
184
|
+
if (error instanceof X402Error) throw error;
|
|
185
|
+
if (error instanceof Error) {
|
|
186
|
+
if (error.message.includes('rejected') || error.message.includes('cancelled')) {
|
|
187
|
+
throw new X402Error('Connection rejected by user', 'WALLET_CONNECTION_REJECTED');
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
throw new X402Error(
|
|
191
|
+
`Failed to connect Lute Wallet: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
192
|
+
'UNKNOWN_ERROR',
|
|
193
|
+
error
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Connect to Pera Wallet (mobile via WalletConnect)
|
|
200
|
+
*/
|
|
201
|
+
private async connectPera(): Promise<string> {
|
|
202
|
+
await loadPeraWallet();
|
|
203
|
+
|
|
94
204
|
if (!PeraWalletConnect) {
|
|
95
205
|
throw new X402Error('Failed to load Pera Wallet SDK', 'WALLET_NOT_FOUND');
|
|
96
206
|
}
|
|
@@ -104,6 +214,7 @@ export class AlgorandProvider implements WalletAdapter {
|
|
|
104
214
|
|
|
105
215
|
if (accounts.length > 0) {
|
|
106
216
|
this.address = accounts[0];
|
|
217
|
+
this.walletType = 'pera';
|
|
107
218
|
return accounts[0];
|
|
108
219
|
}
|
|
109
220
|
|
|
@@ -115,10 +226,12 @@ export class AlgorandProvider implements WalletAdapter {
|
|
|
115
226
|
}
|
|
116
227
|
|
|
117
228
|
this.address = newAccounts[0];
|
|
229
|
+
this.walletType = 'pera';
|
|
118
230
|
|
|
119
231
|
// Set up disconnect handler
|
|
120
232
|
this.peraWallet.connector?.on('disconnect', () => {
|
|
121
233
|
this.address = null;
|
|
234
|
+
this.walletType = null;
|
|
122
235
|
});
|
|
123
236
|
|
|
124
237
|
return newAccounts[0];
|
|
@@ -137,18 +250,27 @@ export class AlgorandProvider implements WalletAdapter {
|
|
|
137
250
|
}
|
|
138
251
|
|
|
139
252
|
/**
|
|
140
|
-
* Disconnect from
|
|
253
|
+
* Disconnect from wallet
|
|
141
254
|
*/
|
|
142
255
|
async disconnect(): Promise<void> {
|
|
143
|
-
if (this.
|
|
256
|
+
if (this.walletType === 'lute' && this.luteWallet) {
|
|
257
|
+
try {
|
|
258
|
+
// Lute doesn't have a disconnect method, just clear state
|
|
259
|
+
} catch {
|
|
260
|
+
// Ignore disconnect errors
|
|
261
|
+
}
|
|
262
|
+
this.luteWallet = null;
|
|
263
|
+
}
|
|
264
|
+
if (this.walletType === 'pera' && this.peraWallet) {
|
|
144
265
|
try {
|
|
145
266
|
await this.peraWallet.disconnect();
|
|
146
267
|
} catch {
|
|
147
268
|
// Ignore disconnect errors
|
|
148
269
|
}
|
|
270
|
+
this.peraWallet = null;
|
|
149
271
|
}
|
|
150
|
-
this.peraWallet = null;
|
|
151
272
|
this.address = null;
|
|
273
|
+
this.walletType = null;
|
|
152
274
|
this.algodClients.clear();
|
|
153
275
|
}
|
|
154
276
|
|
|
@@ -205,7 +327,7 @@ export class AlgorandProvider implements WalletAdapter {
|
|
|
205
327
|
async signPayment(paymentInfo: PaymentInfo, chainConfig: ChainConfig): Promise<string> {
|
|
206
328
|
await loadAlgorandDeps();
|
|
207
329
|
|
|
208
|
-
if (!this.
|
|
330
|
+
if (!this.address || !this.walletType) {
|
|
209
331
|
throw new X402Error('Wallet not connected', 'WALLET_NOT_CONNECTED');
|
|
210
332
|
}
|
|
211
333
|
|
|
@@ -237,15 +359,29 @@ export class AlgorandProvider implements WalletAdapter {
|
|
|
237
359
|
note: new TextEncoder().encode('x402 payment via uvd-x402-sdk'),
|
|
238
360
|
} as any);
|
|
239
361
|
|
|
240
|
-
// Sign with Pera
|
|
241
|
-
|
|
362
|
+
// Sign with the active wallet (Lute or Pera)
|
|
363
|
+
let signedTxn: Uint8Array;
|
|
242
364
|
|
|
243
|
-
if (
|
|
244
|
-
|
|
365
|
+
if (this.walletType === 'lute' && this.luteWallet) {
|
|
366
|
+
// Lute uses signTxns with base64 encoded transactions
|
|
367
|
+
const txnBase64 = uint8ArrayToBase64(txn.toByte());
|
|
368
|
+
const signedTxns = await this.luteWallet.signTxns([{ txn: txnBase64 }]);
|
|
369
|
+
if (!signedTxns || signedTxns.length === 0 || !signedTxns[0]) {
|
|
370
|
+
throw new X402Error('No signed transaction returned', 'SIGNATURE_REJECTED');
|
|
371
|
+
}
|
|
372
|
+
// Lute returns base64 encoded signed transaction
|
|
373
|
+
signedTxn = Uint8Array.from(atob(signedTxns[0]), c => c.charCodeAt(0));
|
|
374
|
+
} else if (this.walletType === 'pera' && this.peraWallet) {
|
|
375
|
+
// Pera uses signTransaction with transaction objects
|
|
376
|
+
const signedTxns = await this.peraWallet.signTransaction([[{ txn }]]);
|
|
377
|
+
if (!signedTxns || signedTxns.length === 0) {
|
|
378
|
+
throw new X402Error('No signed transaction returned', 'SIGNATURE_REJECTED');
|
|
379
|
+
}
|
|
380
|
+
signedTxn = signedTxns[0];
|
|
381
|
+
} else {
|
|
382
|
+
throw new X402Error('No wallet available for signing', 'WALLET_NOT_CONNECTED');
|
|
245
383
|
}
|
|
246
384
|
|
|
247
|
-
const signedTxn = signedTxns[0];
|
|
248
|
-
|
|
249
385
|
const payload: AlgorandPaymentPayload = {
|
|
250
386
|
from: this.address,
|
|
251
387
|
to: recipient,
|