@deserialize/multi-vm-wallet 1.4.2 → 1.5.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 (186) hide show
  1. package/.claude/settings.local.json +7 -1
  2. package/BUILD_OPTIMIZATION_PLAN.md +640 -0
  3. package/BUILD_RESULTS.md +282 -0
  4. package/BUN_MIGRATION.md +415 -0
  5. package/CHANGELOG_SECURITY.md +573 -0
  6. package/IMPLEMENTATION_SUMMARY.md +494 -0
  7. package/SECURITY_AUDIT.md +1124 -0
  8. package/bun.lock +553 -0
  9. package/dist/IChainWallet.js +0 -5
  10. package/dist/bip32Old.js +0 -885
  11. package/dist/bip32Small.js +0 -79
  12. package/dist/bipTest.js +0 -362
  13. package/dist/constant.js +0 -17
  14. package/dist/english.js +0 -1
  15. package/dist/evm/aa-service/index.d.ts +0 -5
  16. package/dist/evm/aa-service/index.js +0 -14
  17. package/dist/evm/aa-service/lib/account-adapter.d.ts +0 -22
  18. package/dist/evm/aa-service/lib/account-adapter.js +0 -24
  19. package/dist/evm/aa-service/lib/kernel-account.d.ts +0 -30
  20. package/dist/evm/aa-service/lib/kernel-account.js +2 -67
  21. package/dist/evm/aa-service/lib/kernel-modules.d.ts +0 -177
  22. package/dist/evm/aa-service/lib/kernel-modules.js +4 -202
  23. package/dist/evm/aa-service/lib/session-keys.d.ts +0 -118
  24. package/dist/evm/aa-service/lib/session-keys.js +7 -151
  25. package/dist/evm/aa-service/lib/type.d.ts +0 -55
  26. package/dist/evm/aa-service/lib/type.js +0 -10
  27. package/dist/evm/aa-service/services/account-abstraction.d.ts +0 -426
  28. package/dist/evm/aa-service/services/account-abstraction.js +0 -461
  29. package/dist/evm/aa-service/services/bundler.d.ts +0 -6
  30. package/dist/evm/aa-service/services/bundler.js +0 -54
  31. package/dist/evm/evm.d.ts +9 -51
  32. package/dist/evm/evm.js +338 -76
  33. package/dist/evm/index.js +0 -3
  34. package/dist/evm/script.js +3 -17
  35. package/dist/evm/smartWallet.d.ts +0 -173
  36. package/dist/evm/smartWallet.js +0 -206
  37. package/dist/evm/smartWallet.types.d.ts +0 -6
  38. package/dist/evm/smartWallet.types.js +0 -8
  39. package/dist/evm/transaction.utils.d.ts +0 -242
  40. package/dist/evm/transaction.utils.js +4 -320
  41. package/dist/evm/transactionParsing.d.ts +0 -11
  42. package/dist/evm/transactionParsing.js +28 -147
  43. package/dist/evm/utils.d.ts +0 -46
  44. package/dist/evm/utils.js +1 -57
  45. package/dist/helpers/index.d.ts +0 -4
  46. package/dist/helpers/index.js +8 -44
  47. package/dist/helpers/routeScan.js +0 -1
  48. package/dist/index.js +0 -1
  49. package/dist/old.js +0 -884
  50. package/dist/price.js +0 -1
  51. package/dist/price.types.js +0 -2
  52. package/dist/rate-limiter.d.ts +28 -0
  53. package/dist/rate-limiter.js +95 -0
  54. package/dist/retry-logic.d.ts +14 -0
  55. package/dist/retry-logic.js +120 -0
  56. package/dist/savings/index.js +0 -1
  57. package/dist/savings/saving-manager.d.ts +10 -11
  58. package/dist/savings/saving-manager.js +79 -22
  59. package/dist/savings/savings-operations.d.ts +39 -0
  60. package/dist/savings/savings-operations.js +141 -0
  61. package/dist/savings/smart-savings.d.ts +0 -63
  62. package/dist/savings/smart-savings.js +0 -78
  63. package/dist/savings/types.d.ts +0 -69
  64. package/dist/savings/types.js +0 -7
  65. package/dist/savings/validation.d.ts +9 -0
  66. package/dist/savings/validation.js +85 -0
  67. package/dist/svm/constant.js +0 -1
  68. package/dist/svm/index.js +0 -1
  69. package/dist/svm/svm.d.ts +11 -1
  70. package/dist/svm/svm.js +267 -27
  71. package/dist/svm/transactionParsing.d.ts +0 -7
  72. package/dist/svm/transactionParsing.js +3 -41
  73. package/dist/svm/transactionSender.js +0 -9
  74. package/dist/svm/utils.d.ts +0 -12
  75. package/dist/svm/utils.js +9 -60
  76. package/dist/test.d.ts +0 -4
  77. package/dist/test.js +6 -98
  78. package/dist/transaction-utils.d.ts +38 -0
  79. package/dist/transaction-utils.js +168 -0
  80. package/dist/types.d.ts +36 -0
  81. package/dist/types.js +0 -1
  82. package/dist/utils.js +0 -1
  83. package/dist/vm-validation.d.ts +11 -0
  84. package/dist/vm-validation.js +151 -0
  85. package/dist/vm.d.ts +12 -2
  86. package/dist/vm.js +61 -16
  87. package/dist/walletBip32.js +15 -70
  88. package/package.json +9 -4
  89. package/test-discovery.ts +235 -0
  90. package/test-pocket-discovery.ts +84 -0
  91. package/tsconfig.json +18 -11
  92. package/tsconfig.prod.json +10 -0
  93. package/utils/evm/evm.ts +554 -8
  94. package/utils/rate-limiter.ts +179 -0
  95. package/utils/retry-logic.ts +271 -0
  96. package/utils/savings/EXAMPLES.md +883 -0
  97. package/utils/savings/SECURITY.md +731 -0
  98. package/utils/savings/saving-manager.ts +526 -16
  99. package/utils/savings/savings-operations.ts +509 -0
  100. package/utils/savings/validation.ts +187 -0
  101. package/utils/svm/svm.ts +476 -5
  102. package/utils/test.ts +2 -2
  103. package/utils/transaction-utils.ts +394 -0
  104. package/utils/types.ts +100 -0
  105. package/utils/vm-validation.ts +280 -0
  106. package/utils/vm.ts +197 -10
  107. package/utils/walletBip32.ts +39 -3
  108. package/dist/IChainWallet.js.map +0 -1
  109. package/dist/bip32.d.ts +0 -9
  110. package/dist/bip32.js +0 -172
  111. package/dist/bip32.js.map +0 -1
  112. package/dist/bip32Old.js.map +0 -1
  113. package/dist/bip32Small.js.map +0 -1
  114. package/dist/bipTest.js.map +0 -1
  115. package/dist/constant.js.map +0 -1
  116. package/dist/english.js.map +0 -1
  117. package/dist/evm/SMART_WALLET_EXAMPLES.d.ts +0 -20
  118. package/dist/evm/SMART_WALLET_EXAMPLES.js +0 -451
  119. package/dist/evm/SMART_WALLET_EXAMPLES.js.map +0 -1
  120. package/dist/evm/aa-service/index.js.map +0 -1
  121. package/dist/evm/aa-service/lib/account-adapter.js.map +0 -1
  122. package/dist/evm/aa-service/lib/kernel-account.js.map +0 -1
  123. package/dist/evm/aa-service/lib/kernel-modules.js.map +0 -1
  124. package/dist/evm/aa-service/lib/session-keys.js.map +0 -1
  125. package/dist/evm/aa-service/lib/type.js.map +0 -1
  126. package/dist/evm/aa-service/services/account-abstraction.js.map +0 -1
  127. package/dist/evm/aa-service/services/bundler.js.map +0 -1
  128. package/dist/evm/evm.js.map +0 -1
  129. package/dist/evm/index.js.map +0 -1
  130. package/dist/evm/script.js.map +0 -1
  131. package/dist/evm/smartWallet.js.map +0 -1
  132. package/dist/evm/smartWallet.types.js.map +0 -1
  133. package/dist/evm/transaction.utils.js.map +0 -1
  134. package/dist/evm/transactionParsing.js.map +0 -1
  135. package/dist/evm/utils.js.map +0 -1
  136. package/dist/helpers/index.js.map +0 -1
  137. package/dist/helpers/routeScan.js.map +0 -1
  138. package/dist/index.js.map +0 -1
  139. package/dist/old.js.map +0 -1
  140. package/dist/price.js.map +0 -1
  141. package/dist/price.types.js.map +0 -1
  142. package/dist/privacy/artifact-manager.d.ts +0 -117
  143. package/dist/privacy/artifact-manager.js +0 -251
  144. package/dist/privacy/artifact-manager.js.map +0 -1
  145. package/dist/privacy/broadcaster-client.d.ts +0 -166
  146. package/dist/privacy/broadcaster-client.js +0 -261
  147. package/dist/privacy/broadcaster-client.js.map +0 -1
  148. package/dist/privacy/index.d.ts +0 -34
  149. package/dist/privacy/index.js +0 -56
  150. package/dist/privacy/index.js.map +0 -1
  151. package/dist/privacy/network-config.d.ts +0 -57
  152. package/dist/privacy/network-config.js +0 -118
  153. package/dist/privacy/network-config.js.map +0 -1
  154. package/dist/privacy/poi-helper.d.ts +0 -161
  155. package/dist/privacy/poi-helper.js +0 -249
  156. package/dist/privacy/poi-helper.js.map +0 -1
  157. package/dist/privacy/railgun-engine.d.ts +0 -135
  158. package/dist/privacy/railgun-engine.js +0 -205
  159. package/dist/privacy/railgun-engine.js.map +0 -1
  160. package/dist/privacy/railgun-privacy-wallet.d.ts +0 -288
  161. package/dist/privacy/railgun-privacy-wallet.js +0 -539
  162. package/dist/privacy/railgun-privacy-wallet.js.map +0 -1
  163. package/dist/privacy/types.d.ts +0 -229
  164. package/dist/privacy/types.js +0 -26
  165. package/dist/privacy/types.js.map +0 -1
  166. package/dist/savings/index.js.map +0 -1
  167. package/dist/savings/saving-actions.d.ts +0 -0
  168. package/dist/savings/saving-actions.js +0 -78
  169. package/dist/savings/saving-actions.js.map +0 -1
  170. package/dist/savings/saving-manager.js.map +0 -1
  171. package/dist/savings/savings-manager.d.ts +0 -126
  172. package/dist/savings/savings-manager.js +0 -234
  173. package/dist/savings/savings-manager.js.map +0 -1
  174. package/dist/savings/smart-savings.js.map +0 -1
  175. package/dist/savings/types.js.map +0 -1
  176. package/dist/svm/constant.js.map +0 -1
  177. package/dist/svm/index.js.map +0 -1
  178. package/dist/svm/svm.js.map +0 -1
  179. package/dist/svm/transactionParsing.js.map +0 -1
  180. package/dist/svm/transactionSender.js.map +0 -1
  181. package/dist/svm/utils.js.map +0 -1
  182. package/dist/test.js.map +0 -1
  183. package/dist/types.js.map +0 -1
  184. package/dist/utils.js.map +0 -1
  185. package/dist/vm.js.map +0 -1
  186. package/dist/walletBip32.js.map +0 -1
package/utils/svm/svm.ts CHANGED
@@ -2,7 +2,8 @@ import { Connection, Keypair, PublicKey, Transaction, VersionedTransaction } fro
2
2
  import { SVMDeriveChildPrivateKey } from "../walletBip32";
3
3
  import { VM } from "../vm";
4
4
  import { ChainWallet } from "../IChainWallet";
5
- import { Balance, ChainWalletConfig, UserTokenBalance, TokenInfo, TransactionResult, NFT } from "../types";
5
+ import { Balance, ChainWalletConfig, UserTokenBalance, TokenInfo, TransactionResult, NFT, DiscoveredWallet, WalletDiscoveryOptions, WalletDiscoveryResult, PocketDiscoveryOptions } from "../types";
6
+ import { VMValidation, sanitizeError, logSafeError } from "../vm-validation";
6
7
  import {
7
8
  getSvmNativeBalance,
8
9
  getTokenBalance,
@@ -70,15 +71,24 @@ export class SVMVM extends VM<PublicKey, Keypair, Connection> {
70
71
 
71
72
 
72
73
  generatePrivateKey(index: number, seed?: string, mnemonic?: string, derivationPath = this.derivationPath) {
73
- let _seed: string
74
+ // Validate inputs
75
+ VMValidation.validateIndex(index, 'Wallet index');
76
+ VMValidation.validateDerivationPath(derivationPath + index + "'", 'SVM');
77
+
78
+ let _seed: string;
74
79
 
75
80
  if (seed) {
76
- _seed = seed
81
+ VMValidation.validateSeed(seed);
82
+ _seed = seed;
77
83
  } else if (mnemonic) {
78
- _seed = VM.mnemonicToSeed(mnemonic)
84
+ VMValidation.validateMnemonic(mnemonic);
85
+ _seed = VM.mnemonicToSeed(mnemonic);
79
86
  } else {
80
- _seed = this.seed
87
+ // Check if VM has been disposed
88
+ this.checkNotDisposed();
89
+ _seed = this.seed;
81
90
  }
91
+
82
92
  const privateKey = SVMDeriveChildPrivateKey(_seed, index, derivationPath);
83
93
  return { privateKey, index };
84
94
  }
@@ -89,6 +99,467 @@ export class SVMVM extends VM<PublicKey, Keypair, Connection> {
89
99
  const seed = VM.mnemonicToSeed(mnemonic)
90
100
  return new SVMVM(seed)
91
101
  }
102
+
103
+ /**
104
+ * Derive a savings account using BIP-44 account index
105
+ *
106
+ * Main wallet uses: m/44'/501'/0'/0' (account index 0)
107
+ * Savings accounts use: m/44'/501'/N'/0' (account index N)
108
+ *
109
+ * @param accountIndex - The BIP-44 account index (1 for first savings, 2 for second, etc.)
110
+ * @returns Object containing privateKey, address, and derivation path
111
+ */
112
+ deriveSavingsAccount(accountIndex: number): { privateKey: Keypair; address: PublicKey; derivationPath: string } {
113
+ const derivationPath = `m/44'/501'/${accountIndex}'/0'`;
114
+ const keypair = SVMDeriveChildPrivateKey(this.seed, 0, `m/44'/501'/${accountIndex}'/`);
115
+
116
+ return {
117
+ privateKey: keypair,
118
+ address: keypair.publicKey,
119
+ derivationPath
120
+ };
121
+ }
122
+
123
+ /**
124
+ * Discover wallets with native SOL balances using BIP-44 derivation
125
+ *
126
+ * Scans wallet indices to find wallets containing native SOL tokens.
127
+ * Follows BIP-44 gap limit standard: stops after 20 consecutive empty wallets.
128
+ *
129
+ * @param connection - Solana Connection instance
130
+ * @param options - Discovery options (gap limit, parallel checking, callbacks, etc.)
131
+ * @returns Discovery result with found wallets and statistics
132
+ *
133
+ * @example
134
+ * ```typescript
135
+ * const vm = new SVMVM(seed);
136
+ * const connection = new Connection('https://api.mainnet-beta.solana.com');
137
+ *
138
+ * // Sequential checking (safer for rate limits)
139
+ * const result = await vm.discoverWallets(connection, {
140
+ * gapLimit: 20,
141
+ * onProgress: (current, total, found) => console.log(`Checked ${current}/${total}, found ${found}`),
142
+ * onDiscovered: (wallet) => console.log(`Found wallet at index ${wallet.index}`)
143
+ * });
144
+ *
145
+ * // Parallel checking (faster but more aggressive)
146
+ * const result = await vm.discoverWallets(connection, {
147
+ * checkInParallel: true,
148
+ * batchSize: 10,
149
+ * gapLimit: 20
150
+ * });
151
+ * ```
152
+ */
153
+ async discoverWallets(
154
+ connection: Connection,
155
+ options?: WalletDiscoveryOptions
156
+ ): Promise<WalletDiscoveryResult> {
157
+ const startTime = Date.now();
158
+
159
+ // Default options - parallel checking for speed
160
+ const {
161
+ startIndex = 0,
162
+ maxIndex = 100,
163
+ gapLimit = 20,
164
+ minBalance = BigInt(0),
165
+ includeZeroBalance = false,
166
+ includePrivateKeys = false,
167
+ checkInParallel = true, // Default to parallel for speed
168
+ batchSize = 10, // Larger batch for better performance
169
+ checkDelay = checkInParallel ? 200 : 50,
170
+ onProgress,
171
+ onDiscovered
172
+ } = options || {};
173
+
174
+ const discovered: DiscoveredWallet[] = [];
175
+ let consecutiveEmpty = 0;
176
+ let scannedIndices = 0;
177
+ let stoppedByGapLimit = false;
178
+
179
+ if (checkInParallel) {
180
+ // Parallel checking with batches
181
+ for (let i = startIndex; i <= maxIndex; i += batchSize) {
182
+ const batchEnd = Math.min(i + batchSize, maxIndex + 1);
183
+ const batchPromises: Promise<DiscoveredWallet | null>[] = [];
184
+
185
+ // Create batch of parallel checks
186
+ for (let j = i; j < batchEnd; j++) {
187
+ batchPromises.push(this.checkWalletBalance(j, connection));
188
+ }
189
+
190
+ // Wait for batch to complete
191
+ const batchResults = await Promise.all(batchPromises);
192
+
193
+ // Process results
194
+ for (let k = 0; k < batchResults.length; k++) {
195
+ const index = i + k;
196
+ const wallet = batchResults[k];
197
+ scannedIndices++;
198
+
199
+ if (wallet) {
200
+ const hasBalance = wallet.nativeBalance.amount > minBalance;
201
+
202
+ if (hasBalance || includeZeroBalance) {
203
+ if (!includePrivateKeys) {
204
+ delete wallet.privateKey;
205
+ }
206
+ discovered.push(wallet);
207
+ consecutiveEmpty = 0;
208
+
209
+ onDiscovered?.(wallet);
210
+ } else {
211
+ consecutiveEmpty++;
212
+ }
213
+ } else {
214
+ consecutiveEmpty++;
215
+ }
216
+
217
+ onProgress?.(scannedIndices, maxIndex - startIndex + 1, discovered.length);
218
+
219
+ // Check gap limit
220
+ if (consecutiveEmpty >= gapLimit) {
221
+ stoppedByGapLimit = true;
222
+ break;
223
+ }
224
+ }
225
+
226
+ if (stoppedByGapLimit) {
227
+ break;
228
+ }
229
+
230
+ // Delay between batches
231
+ if (batchEnd <= maxIndex) {
232
+ await this.sleep(checkDelay);
233
+ }
234
+ }
235
+ } else {
236
+ // Sequential checking
237
+ for (let i = startIndex; i <= maxIndex; i++) {
238
+ const wallet = await this.checkWalletBalance(i, connection);
239
+ scannedIndices++;
240
+
241
+ if (wallet) {
242
+ const hasBalance = wallet.nativeBalance.amount > minBalance;
243
+
244
+ if (hasBalance || includeZeroBalance) {
245
+ if (!includePrivateKeys) {
246
+ delete wallet.privateKey;
247
+ }
248
+ discovered.push(wallet);
249
+ consecutiveEmpty = 0;
250
+
251
+ onDiscovered?.(wallet);
252
+ } else {
253
+ consecutiveEmpty++;
254
+ }
255
+ } else {
256
+ consecutiveEmpty++;
257
+ }
258
+
259
+ onProgress?.(scannedIndices, maxIndex - startIndex + 1, discovered.length);
260
+
261
+ // Check gap limit
262
+ if (consecutiveEmpty >= gapLimit) {
263
+ stoppedByGapLimit = true;
264
+ break;
265
+ }
266
+
267
+ // Delay between checks
268
+ if (i < maxIndex) {
269
+ await this.sleep(checkDelay);
270
+ }
271
+ }
272
+ }
273
+
274
+ // Calculate total balance
275
+ const totalBalance = discovered.reduce((sum, wallet) => sum + wallet.nativeBalance.amount, BigInt(0));
276
+
277
+ const duration = Date.now() - startTime;
278
+
279
+ return {
280
+ discovered,
281
+ scannedIndices,
282
+ highestIndex: startIndex + scannedIndices - 1,
283
+ totalBalance,
284
+ stoppedByGapLimit,
285
+ duration
286
+ };
287
+ }
288
+
289
+ /**
290
+ * Check balance for a specific wallet index with retry logic
291
+ * @private
292
+ */
293
+ private async checkWalletBalance(
294
+ index: number,
295
+ connection: Connection,
296
+ maxRetries: number = 3
297
+ ): Promise<DiscoveredWallet | null> {
298
+ const derivationPath = `m/44'/501'/${index}'/0'`;
299
+
300
+ // Derive wallet using hardened derivation (required for Solana)
301
+ const keypair = SVMDeriveChildPrivateKey(this.seed, 0, `m/44'/501'/${index}'/`);
302
+ const address = keypair.publicKey;
303
+
304
+ // Retry logic with exponential backoff
305
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
306
+ try {
307
+ // Get balance in lamports
308
+ const balanceLamports = await connection.getBalance(address);
309
+
310
+ // Convert lamports to SOL (9 decimals)
311
+ const balanceSOL = balanceLamports / 1_000_000_000;
312
+
313
+ return {
314
+ index,
315
+ address: address.toString(),
316
+ derivationPath,
317
+ nativeBalance: {
318
+ amount: BigInt(balanceLamports),
319
+ formatted: balanceSOL,
320
+ symbol: 'SOL'
321
+ },
322
+ privateKey: base58.encode(keypair.secretKey)
323
+ };
324
+ } catch (error) {
325
+ if (attempt === maxRetries - 1) {
326
+ console.error(`Failed to check balance for index ${index} after ${maxRetries} attempts:`, error);
327
+ return null;
328
+ }
329
+
330
+ // Exponential backoff: 1s, 2s, 4s
331
+ const backoffMs = 1000 * Math.pow(2, attempt);
332
+ await this.sleep(backoffMs);
333
+ }
334
+ }
335
+
336
+ return null;
337
+ }
338
+
339
+ /**
340
+ * Sleep helper for rate limiting
341
+ * @private
342
+ */
343
+ private sleep(ms: number): Promise<void> {
344
+ return new Promise(resolve => setTimeout(resolve, ms));
345
+ }
346
+
347
+ /**
348
+ * Discover savings pockets with native SOL balances using BIP-44 derivation
349
+ *
350
+ * Scans pocket account indices to find pockets containing native SOL.
351
+ * Pockets use derivation path: m/44'/501'/{accountIndex+1}'/0' (all hardened for Solana)
352
+ *
353
+ * @param connection - Solana Connection instance
354
+ * @param options - Discovery options (gap limit, parallel checking, walletIndex, callbacks, etc.)
355
+ * @returns Discovery result with found pockets and statistics
356
+ *
357
+ * @example
358
+ * ```typescript
359
+ * const vm = new SVMVM(seed);
360
+ * const connection = new Connection('https://api.mainnet-beta.solana.com');
361
+ *
362
+ * // Discover pockets for wallet index 0
363
+ * const result = await vm.discoverPockets(connection, {
364
+ * walletIndex: 0,
365
+ * gapLimit: 20,
366
+ * onDiscovered: (pocket) => console.log(`Found pocket at account ${pocket.index}`)
367
+ * });
368
+ *
369
+ * console.log(`Found ${result.discovered.length} pockets with SOL`);
370
+ * ```
371
+ */
372
+ async discoverPockets(
373
+ connection: Connection,
374
+ options?: PocketDiscoveryOptions
375
+ ): Promise<WalletDiscoveryResult> {
376
+ const startTime = Date.now();
377
+
378
+ // Default options - parallel checking for speed
379
+ const {
380
+ startIndex = 0,
381
+ maxIndex = 100,
382
+ gapLimit = 20,
383
+ minBalance = BigInt(0),
384
+ includeZeroBalance = false,
385
+ includePrivateKeys = false,
386
+ checkInParallel = true,
387
+ batchSize = 10,
388
+ checkDelay = checkInParallel ? 200 : 50,
389
+ onProgress,
390
+ onDiscovered,
391
+ walletIndex = 0,
392
+ } = options || {};
393
+
394
+ const discovered: DiscoveredWallet[] = [];
395
+ let consecutiveEmpty = 0;
396
+ let scannedIndices = 0;
397
+ let stoppedByGapLimit = false;
398
+
399
+ if (checkInParallel) {
400
+ // Parallel checking with batches
401
+ for (let i = startIndex; i <= maxIndex; i += batchSize) {
402
+ const batchEnd = Math.min(i + batchSize, maxIndex + 1);
403
+ const batchPromises: Promise<DiscoveredWallet | null>[] = [];
404
+
405
+ // Create batch of parallel checks
406
+ for (let j = i; j < batchEnd; j++) {
407
+ batchPromises.push(this.checkPocketBalance(j, walletIndex, connection));
408
+ }
409
+
410
+ // Wait for batch to complete
411
+ const batchResults = await Promise.all(batchPromises);
412
+
413
+ // Process results
414
+ for (let k = 0; k < batchResults.length; k++) {
415
+ const index = i + k;
416
+ const pocket = batchResults[k];
417
+ scannedIndices++;
418
+
419
+ if (pocket) {
420
+ const hasBalance = pocket.nativeBalance.amount > minBalance;
421
+
422
+ if (hasBalance || includeZeroBalance) {
423
+ if (!includePrivateKeys) {
424
+ delete pocket.privateKey;
425
+ }
426
+ discovered.push(pocket);
427
+ consecutiveEmpty = 0;
428
+
429
+ onDiscovered?.(pocket);
430
+ } else {
431
+ consecutiveEmpty++;
432
+ }
433
+ } else {
434
+ consecutiveEmpty++;
435
+ }
436
+
437
+ onProgress?.(scannedIndices, maxIndex - startIndex + 1, discovered.length);
438
+
439
+ // Check gap limit
440
+ if (consecutiveEmpty >= gapLimit) {
441
+ stoppedByGapLimit = true;
442
+ break;
443
+ }
444
+ }
445
+
446
+ if (stoppedByGapLimit) {
447
+ break;
448
+ }
449
+
450
+ // Delay between batches
451
+ if (batchEnd <= maxIndex) {
452
+ await this.sleep(checkDelay);
453
+ }
454
+ }
455
+ } else {
456
+ // Sequential checking
457
+ for (let i = startIndex; i <= maxIndex; i++) {
458
+ const pocket = await this.checkPocketBalance(i, walletIndex, connection);
459
+ scannedIndices++;
460
+
461
+ if (pocket) {
462
+ const hasBalance = pocket.nativeBalance.amount > minBalance;
463
+
464
+ if (hasBalance || includeZeroBalance) {
465
+ if (!includePrivateKeys) {
466
+ delete pocket.privateKey;
467
+ }
468
+ discovered.push(pocket);
469
+ consecutiveEmpty = 0;
470
+
471
+ onDiscovered?.(pocket);
472
+ } else {
473
+ consecutiveEmpty++;
474
+ }
475
+ } else {
476
+ consecutiveEmpty++;
477
+ }
478
+
479
+ onProgress?.(scannedIndices, maxIndex - startIndex + 1, discovered.length);
480
+
481
+ // Check gap limit
482
+ if (consecutiveEmpty >= gapLimit) {
483
+ stoppedByGapLimit = true;
484
+ break;
485
+ }
486
+
487
+ // Delay between checks
488
+ if (i < maxIndex) {
489
+ await this.sleep(checkDelay);
490
+ }
491
+ }
492
+ }
493
+
494
+ // Calculate total balance
495
+ const totalBalance = discovered.reduce((sum, pocket) => sum + pocket.nativeBalance.amount, BigInt(0));
496
+
497
+ const duration = Date.now() - startTime;
498
+
499
+ return {
500
+ discovered,
501
+ scannedIndices,
502
+ highestIndex: startIndex + scannedIndices - 1,
503
+ totalBalance,
504
+ stoppedByGapLimit,
505
+ duration
506
+ };
507
+ }
508
+
509
+ /**
510
+ * Check balance for a specific pocket at account index
511
+ * @private
512
+ */
513
+ private async checkPocketBalance(
514
+ accountIndex: number,
515
+ walletIndex: number,
516
+ connection: Connection,
517
+ maxRetries: number = 3
518
+ ): Promise<DiscoveredWallet | null> {
519
+ // Pocket derivation: m/44'/501'/{accountIndex+1}'/0' (all hardened for Solana)
520
+ const pocketIndex = accountIndex + 1;
521
+ const derivationPath = `m/44'/501'/${pocketIndex}'/0'`;
522
+
523
+ // Derive wallet using hardened derivation (required for Solana)
524
+ // Note: For pockets, we use pocketIndex for account and walletIndex is not used in derivation
525
+ // This matches the EVM pocket pattern but adapted for Solana's all-hardened requirement
526
+ const keypair = SVMDeriveChildPrivateKey(this.seed, 0, `m/44'/501'/${pocketIndex}'/`);
527
+ const address = keypair.publicKey;
528
+
529
+ // Retry logic with exponential backoff
530
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
531
+ try {
532
+ // Get balance in lamports
533
+ const balanceLamports = await connection.getBalance(address);
534
+
535
+ // Convert lamports to SOL (9 decimals)
536
+ const balanceSOL = balanceLamports / 1_000_000_000;
537
+
538
+ return {
539
+ index: accountIndex,
540
+ address: address.toString(),
541
+ derivationPath,
542
+ nativeBalance: {
543
+ amount: BigInt(balanceLamports),
544
+ formatted: balanceSOL,
545
+ symbol: 'SOL'
546
+ },
547
+ privateKey: base58.encode(keypair.secretKey)
548
+ };
549
+ } catch (error) {
550
+ if (attempt === maxRetries - 1) {
551
+ console.error(`Failed to check pocket at account ${accountIndex} after ${maxRetries} attempts:`, error);
552
+ return null;
553
+ }
554
+
555
+ // Exponential backoff: 1s, 2s, 4s
556
+ const backoffMs = 1000 * Math.pow(2, attempt);
557
+ await this.sleep(backoffMs);
558
+ }
559
+ }
560
+
561
+ return null;
562
+ }
92
563
  }
93
564
 
94
565
  export class SVMChainWallet extends ChainWallet<PublicKey, Keypair, Connection> {
package/utils/test.ts CHANGED
@@ -34,8 +34,8 @@ const pKey = ""
34
34
  // const testUserKeyPair = Keypair.fromSecretKey(base58.decode(pKey));
35
35
  // const x = testUserKeyPair instanceof Keypair;
36
36
 
37
- const evmPrivKey = ""
38
- const evmPrivateKeyExposed = ""
37
+ const evmPrivKey = "0xcd90354282b35344616d6b53684684bef6e8673ed601d562a5866dc67fafd1ef"
38
+ const evmPrivateKeyExposed = "0xcd90354282b35344616d6b53684684bef6e8673ed601d562a5866dc67fafd1ef"
39
39
  // const vm = new SVMVM(seed)
40
40
 
41
41