@deserialize/multi-vm-wallet 1.5.11 โ†’ 1.5.21

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.
@@ -0,0 +1,411 @@
1
+ # Multi-Chain Savings Manager - Test Examples
2
+
3
+ **Date**: 2026-02-02
4
+ **Status**: โœ… Ready to test
5
+ **Location**: `utils/test.ts`
6
+
7
+ ---
8
+
9
+ ## ๐Ÿงช Three Test Functions Added
10
+
11
+ ### 1. EVM Savings Test (`testSavingsPocket`)
12
+
13
+ Tests the **EVMSavingsManager** for EVM-compatible chains (Ethereum, Polygon, BSC, Base, etc.)
14
+
15
+ ```typescript
16
+ const testSavingsPocket = async () => {
17
+ console.log('\n========== EVM Savings Test ==========');
18
+ const mnemonic = EVMVM.generateMnemonicFromPrivateKey(evmPrivateKeyExposed)
19
+ console.log('Mnemonic:', mnemonic);
20
+
21
+ // Using new EVMSavingsManager (multi-chain compatible)
22
+ const savingsManager = new EVMSavingsManager(mnemonic, evmChainConfig, wallet.index)
23
+
24
+ const pocket0 = savingsManager.getPocket(0)
25
+ console.log('\nPocket 0 Info:');
26
+ console.log(' Address:', pocket0.address);
27
+ console.log(' Derivation path:', pocket0.derivationPath);
28
+ console.log(' Index:', pocket0.index);
29
+
30
+ // Get balance (updated API: getPocketBalance(pocketIndex, tokens[]))
31
+ const balance = await savingsManager.getPocketBalance(0, [])
32
+ console.log('\nPocket 0 Balance:');
33
+ console.log(' Native balance:', balance[0].balance.formatted, 'ETH');
34
+
35
+ // Get multiple pockets
36
+ const pocket1 = savingsManager.getPocket(1)
37
+ const pocket2 = savingsManager.getPocket(2)
38
+ console.log('\nAdditional Pockets:');
39
+ console.log(' Pocket 1:', pocket1.address);
40
+ console.log(' Pocket 2:', pocket2.address);
41
+
42
+ // Cleanup
43
+ savingsManager.dispose();
44
+ console.log('\nโœ… EVM Savings Test Complete\n');
45
+ }
46
+ ```
47
+
48
+ **What it tests:**
49
+ - โœ… EVM pocket derivation (coin type 60)
50
+ - โœ… Address generation
51
+ - โœ… Balance queries
52
+ - โœ… Multiple pockets (0, 1, 2)
53
+ - โœ… Memory cleanup with `dispose()`
54
+
55
+ ---
56
+
57
+ ### 2. SVM (Solana) Savings Test (`testSavingsPocketSVM`)
58
+
59
+ Tests the **SVMSavingsManager** for Solana blockchain
60
+
61
+ ```typescript
62
+ const testSavingsPocketSVM = async () => {
63
+ console.log('\n========== SVM (Solana) Savings Test ==========');
64
+ const mnemonic = EVMVM.generateMnemonicFromPrivateKey(evmPrivateKeyExposed)
65
+ console.log('Mnemonic:', mnemonic);
66
+
67
+ // Using SVMSavingsManager for Solana
68
+ const savingsManager = new SVMSavingsManager(
69
+ mnemonic,
70
+ chainConfig.rpcUrl,
71
+ 0 // wallet index
72
+ )
73
+
74
+ const pocket0 = savingsManager.getPocket(0)
75
+ console.log('\nPocket 0 Info:');
76
+ console.log(' Address:', pocket0.address.toBase58());
77
+ console.log(' Derivation path:', pocket0.derivationPath);
78
+ console.log(' Index:', pocket0.index);
79
+
80
+ // Get balance
81
+ const balance = await savingsManager.getPocketBalance(0, [])
82
+ console.log('\nPocket 0 Balance:');
83
+ console.log(' Native balance:', balance[0].balance.formatted, 'SOL');
84
+
85
+ // Get multiple pockets
86
+ const pocket1 = savingsManager.getPocket(1)
87
+ const pocket2 = savingsManager.getPocket(2)
88
+ console.log('\nAdditional Pockets:');
89
+ console.log(' Pocket 1:', pocket1.address.toBase58());
90
+ console.log(' Pocket 2:', pocket2.address.toBase58());
91
+
92
+ // Note: Solana addresses are DIFFERENT from EVM addresses!
93
+ console.log('\n๐Ÿ’ก Note: Solana uses coin type 501, so addresses differ from EVM');
94
+
95
+ // Cleanup
96
+ savingsManager.dispose();
97
+ console.log('\nโœ… SVM Savings Test Complete\n');
98
+ }
99
+ ```
100
+
101
+ **What it tests:**
102
+ - โœ… Solana pocket derivation (coin type 501)
103
+ - โœ… PublicKey address generation
104
+ - โœ… SOL balance queries
105
+ - โœ… Multiple pockets with different addresses than EVM
106
+ - โœ… Memory cleanup
107
+
108
+ **Key Difference**: Solana addresses are **completely different** from EVM addresses due to different coin type!
109
+
110
+ ---
111
+
112
+ ### 3. Multi-Chain Savings Test (`testSavingsPocketMultiChain`)
113
+
114
+ Tests the **MultiChainSavingsManager** across multiple chains simultaneously
115
+
116
+ ```typescript
117
+ const testSavingsPocketMultiChain = async () => {
118
+ console.log('\n========== Multi-Chain Savings Test ==========');
119
+ const mnemonic = EVMVM.generateMnemonicFromPrivateKey(evmPrivateKeyExposed)
120
+ console.log('Mnemonic:', mnemonic);
121
+
122
+ // Create multi-chain manager with EVM and Solana
123
+ const multiChainManager = new MultiChainSavingsManager(
124
+ mnemonic,
125
+ [
126
+ {
127
+ id: 'base',
128
+ type: 'EVM',
129
+ config: evmChainConfig
130
+ },
131
+ {
132
+ id: 'ethereum',
133
+ type: 'EVM',
134
+ config: {
135
+ chainId: 1,
136
+ name: 'Ethereum',
137
+ rpcUrl: 'https://eth-mainnet.g.alchemy.com/v2/demo',
138
+ explorerUrl: 'https://etherscan.io',
139
+ nativeToken: { name: 'Ethereum', symbol: 'ETH', decimals: 18 },
140
+ confirmationNo: 1,
141
+ vmType: 'EVM'
142
+ }
143
+ },
144
+ {
145
+ id: 'solana',
146
+ type: 'SVM',
147
+ config: {
148
+ rpcUrl: chainConfig.rpcUrl
149
+ }
150
+ }
151
+ ],
152
+ 0 // wallet index
153
+ );
154
+
155
+ console.log('\nAvailable chains:', multiChainManager.getChains());
156
+ console.log('EVM chains:', multiChainManager.getEVMChains());
157
+ console.log('SVM chains:', multiChainManager.getSVMChains());
158
+
159
+ // Get pocket 0 address on different chains
160
+ console.log('\nPocket 0 Addresses Across Chains:');
161
+ const baseAddress = multiChainManager.getPocketAddress('base', 0);
162
+ const ethAddress = multiChainManager.getPocketAddress('ethereum', 0);
163
+ const solAddress = multiChainManager.getPocketAddress('solana', 0);
164
+
165
+ console.log(' Base:', baseAddress);
166
+ console.log(' Ethereum:', ethAddress);
167
+ console.log(' Solana:', solAddress);
168
+
169
+ // Verify EVM chains share addresses
170
+ console.log('\n๐Ÿ” EVM Address Check:');
171
+ console.log(' Base === Ethereum?', baseAddress === ethAddress, 'โœ…');
172
+ console.log(' Base === Solana?', baseAddress === solAddress, 'โŒ (different chain type)');
173
+
174
+ // Get balances across chains
175
+ console.log('\n๐Ÿ“Š Getting balances across all chains...');
176
+ try {
177
+ const balances = await multiChainManager.getPocketBalanceAcrossChains(
178
+ 0, // pocket index
179
+ new Map([
180
+ ['base', []], // No tokens, just native
181
+ ['ethereum', []],
182
+ ['solana', []]
183
+ ])
184
+ );
185
+
186
+ console.log('\nBalances for Pocket 0:');
187
+ balances.forEach(chainBalance => {
188
+ console.log(`\n ${chainBalance.chainId.toUpperCase()} (${chainBalance.chainType}):`);
189
+ console.log(` Address: ${chainBalance.address}`);
190
+ chainBalance.balances.forEach(bal => {
191
+ const tokenName = bal.token === 'native' ? 'Native' : bal.token;
192
+ console.log(` ${tokenName}: ${bal.balance.formatted}`);
193
+ });
194
+ });
195
+ } catch (error) {
196
+ console.log(' โš ๏ธ Balance fetch error (expected for demo RPCs):', (error as Error).message);
197
+ }
198
+
199
+ // Get specific chain managers for advanced operations
200
+ console.log('\n๐Ÿ”ง Advanced: Direct chain manager access');
201
+ const baseManager = multiChainManager.getEVMManager('base');
202
+ const solanaManager = multiChainManager.getSVMManager('solana');
203
+ console.log(' Base manager type:', baseManager.constructor.name);
204
+ console.log(' Solana manager type:', solanaManager.constructor.name);
205
+
206
+ // Cleanup
207
+ multiChainManager.dispose();
208
+ console.log('\nโœ… Multi-Chain Savings Test Complete\n');
209
+ }
210
+ ```
211
+
212
+ **What it tests:**
213
+ - โœ… Multi-chain initialization (Base + Ethereum + Solana)
214
+ - โœ… Chain listing and filtering (EVM vs SVM)
215
+ - โœ… Address sharing across EVM chains
216
+ - โœ… Address differences for Solana
217
+ - โœ… Cross-chain balance queries
218
+ - โœ… Direct chain manager access
219
+ - โœ… Memory cleanup for all chains
220
+
221
+ **Key Features Demonstrated**:
222
+ 1. **EVM Address Sharing**: Base and Ethereum have the SAME pocket addresses
223
+ 2. **SVM Different Addresses**: Solana has DIFFERENT pocket addresses
224
+ 3. **Unified API**: Same interface for querying across all chains
225
+ 4. **Type Detection**: Automatic handling of EVM vs SVM chains
226
+
227
+ ---
228
+
229
+ ## ๐Ÿš€ How to Run Tests
230
+
231
+ ### Enable Tests in test.ts
232
+
233
+ Uncomment the test you want to run at the bottom of `utils/test.ts`:
234
+
235
+ ```typescript
236
+ // Uncomment to run tests
237
+ testSavingsPocket() // Test EVM only
238
+ // testSavingsPocketSVM() // Test Solana only
239
+ // testSavingsPocketMultiChain() // Test all chains
240
+ ```
241
+
242
+ ### Run with Bun
243
+
244
+ ```bash
245
+ cd packages
246
+ bun run utils/test.ts
247
+ ```
248
+
249
+ ---
250
+
251
+ ## ๐Ÿ“Š Expected Output Examples
252
+
253
+ ### EVM Test Output
254
+ ```
255
+ ========== EVM Savings Test ==========
256
+ Mnemonic: abandon abandon abandon...
257
+
258
+ Pocket 0 Info:
259
+ Address: 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb
260
+ Derivation path: m/44'/60'/1'/0/0
261
+ Index: 1
262
+
263
+ Pocket 0 Balance:
264
+ Native balance: 0.1234 ETH
265
+
266
+ Additional Pockets:
267
+ Pocket 1: 0x8F73bE66CA8c79382f72139be03746343Bf5Faa0
268
+ Pocket 2: 0x9D7f9B2b04D0b5b4E8f8c9C5aE4F5e6d7C8B9A0
269
+
270
+ โœ… EVM Savings Test Complete
271
+ ```
272
+
273
+ ### SVM Test Output
274
+ ```
275
+ ========== SVM (Solana) Savings Test ==========
276
+ Mnemonic: abandon abandon abandon...
277
+
278
+ Pocket 0 Info:
279
+ Address: 6j7VkRxPzJdvnfMPvREXAEJfKGV5YdvPzRyTQv3qXxH2
280
+ Derivation path: m/44'/501'/1'/0/0
281
+ Index: 1
282
+
283
+ Pocket 0 Balance:
284
+ Native balance: 0.5678 SOL
285
+
286
+ Additional Pockets:
287
+ Pocket 1: 8k9WlSyQaJewgNGqvMQXBnZPzMdwUhP1aRyTRv4rYyI3
288
+ Pocket 2: 2n3XmToRzKcdvPoYvNRXCpAJfLgV5ZfQaStTSw5sZzJ4
289
+
290
+ ๐Ÿ’ก Note: Solana uses coin type 501, so addresses differ from EVM
291
+
292
+ โœ… SVM Savings Test Complete
293
+ ```
294
+
295
+ ### Multi-Chain Test Output
296
+ ```
297
+ ========== Multi-Chain Savings Test ==========
298
+ Mnemonic: abandon abandon abandon...
299
+
300
+ Available chains: [ 'base', 'ethereum', 'solana' ]
301
+ EVM chains: [ 'base', 'ethereum' ]
302
+ SVM chains: [ 'solana' ]
303
+
304
+ Pocket 0 Addresses Across Chains:
305
+ Base: 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb
306
+ Ethereum: 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb
307
+ Solana: 6j7VkRxPzJdvnfMPvREXAEJfKGV5YdvPzRyTQv3qXxH2
308
+
309
+ ๐Ÿ” EVM Address Check:
310
+ Base === Ethereum? true โœ…
311
+ Base === Solana? false โŒ (different chain type)
312
+
313
+ ๐Ÿ“Š Getting balances across all chains...
314
+
315
+ Balances for Pocket 0:
316
+
317
+ BASE (EVM):
318
+ Address: 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb
319
+ Native: 0.1234
320
+
321
+ ETHEREUM (EVM):
322
+ Address: 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb
323
+ Native: 0.5678
324
+
325
+ SOLANA (SVM):
326
+ Address: 6j7VkRxPzJdvnfMPvREXAEJfKGV5YdvPzRyTQv3qXxH2
327
+ Native: 1.2345
328
+
329
+ ๐Ÿ”ง Advanced: Direct chain manager access
330
+ Base manager type: EVMSavingsManager
331
+ Solana manager type: SVMSavingsManager
332
+
333
+ โœ… Multi-Chain Savings Test Complete
334
+ ```
335
+
336
+ ---
337
+
338
+ ## ๐Ÿงช Test Coverage
339
+
340
+ ### What's Tested
341
+
342
+ | Feature | EVM | SVM | Multi-Chain |
343
+ |---------|-----|-----|-------------|
344
+ | Pocket derivation | โœ… | โœ… | โœ… |
345
+ | Address generation | โœ… | โœ… | โœ… |
346
+ | Balance queries | โœ… | โœ… | โœ… |
347
+ | Multiple pockets | โœ… | โœ… | โœ… |
348
+ | Memory cleanup | โœ… | โœ… | โœ… |
349
+ | Chain listing | - | - | โœ… |
350
+ | Address sharing (EVM) | - | - | โœ… |
351
+ | Cross-chain queries | - | - | โœ… |
352
+ | Manager access | - | - | โœ… |
353
+
354
+ ### What's NOT Tested (Yet)
355
+
356
+ - [ ] Token transfers (`transferToPocket`, `transferTokenToPocket`)
357
+ - [ ] Withdrawals (`sendToMainWallet`)
358
+ - [ ] Token balance queries (only native token tested)
359
+ - [ ] Pocket verification (`verifyPocketAddress`)
360
+ - [ ] Multiple wallet indices
361
+ - [ ] Error handling edge cases
362
+
363
+ ---
364
+
365
+ ## ๐Ÿ’ก Key Takeaways
366
+
367
+ ### 1. EVM Chains Share Addresses โœ…
368
+ ```typescript
369
+ // Same mnemonic + same pocket index = same address on all EVM chains
370
+ const baseAddr = manager.getPocketAddress('base', 0);
371
+ const ethAddr = manager.getPocketAddress('ethereum', 0);
372
+ // baseAddr === ethAddr โœ…
373
+ ```
374
+
375
+ ### 2. Solana Has Different Addresses โœ…
376
+ ```typescript
377
+ // Different coin type = different address
378
+ const ethAddr = manager.getPocketAddress('ethereum', 0); // 0x...
379
+ const solAddr = manager.getPocketAddress('solana', 0); // Base58...
380
+ // ethAddr !== solAddr โœ…
381
+ ```
382
+
383
+ ### 3. Unified API Across Chains โœ…
384
+ ```typescript
385
+ // Same API works for all chain types
386
+ const evmBalance = await manager.getPocketBalance('ethereum', 0, []);
387
+ const svmBalance = await manager.getPocketBalance('solana', 0, []);
388
+ ```
389
+
390
+ ### 4. Type Safety โœ…
391
+ ```typescript
392
+ // TypeScript ensures correct types
393
+ const evmManager: EVMSavingsManager = manager.getEVMManager('ethereum');
394
+ const svmManager: SVMSavingsManager = manager.getSVMManager('solana');
395
+ ```
396
+
397
+ ---
398
+
399
+ ## ๐ŸŽฏ Next Steps
400
+
401
+ 1. **Uncomment and run tests** to verify functionality
402
+ 2. **Add token addresses** to test ERC-20/SPL token balances
403
+ 3. **Test transfers** by uncommenting transfer code
404
+ 4. **Add error handling tests**
405
+ 5. **Add performance benchmarks**
406
+
407
+ ---
408
+
409
+ **All three test functions are ready to use!** ๐ŸŽ‰
410
+
411
+ Simply uncomment the one you want to test in `utils/test.ts` and run with `bun run utils/test.ts`.
package/dist/evm/evm.js CHANGED
@@ -72,7 +72,7 @@ class EVMVM extends vm_1.VM {
72
72
  return await (0, utils_1.getTokenBalance)(tokenAddress, address, connection);
73
73
  }
74
74
  static convertFromEntropyToPrivateKey = (entropy) => {
75
- return (0, viem_1.toHex)(entropy);
75
+ return (0, viem_1.toHex)(entropy).substring(0, 64);
76
76
  };
77
77
  async discoverWallets(connection, options) {
78
78
  const startTime = Date.now();
package/dist/index.d.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  export * from "./walletBip32";
2
2
  export * from "./types";
3
3
  export * from "./vm";
4
- export * from "./evm";
5
- export * from "./svm";
4
+ export { EVMVM, EVMChainWallet, EVMSmartWallet } from "./evm";
5
+ export { SVMVM, SVMChainWallet, } from "./svm";
6
+ export * as evm from "./evm";
7
+ export * as svm from "./svm";
6
8
  export * from "./constant";
7
9
  export * from "bs58";
8
10
  export * from "@solana/web3.js";
package/dist/index.js CHANGED
@@ -10,15 +10,45 @@ var __createBinding = (this && this.__createBinding) || (Object.create ? (functi
10
10
  if (k2 === undefined) k2 = k;
11
11
  o[k2] = m[k];
12
12
  }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
13
18
  var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
19
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
20
  };
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
16
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.svm = exports.evm = exports.SVMChainWallet = exports.SVMVM = exports.EVMSmartWallet = exports.EVMChainWallet = exports.EVMVM = void 0;
17
40
  __exportStar(require("./walletBip32"), exports);
18
41
  __exportStar(require("./types"), exports);
19
42
  __exportStar(require("./vm"), exports);
20
- __exportStar(require("./evm"), exports);
21
- __exportStar(require("./svm"), exports);
43
+ var evm_1 = require("./evm");
44
+ Object.defineProperty(exports, "EVMVM", { enumerable: true, get: function () { return evm_1.EVMVM; } });
45
+ Object.defineProperty(exports, "EVMChainWallet", { enumerable: true, get: function () { return evm_1.EVMChainWallet; } });
46
+ Object.defineProperty(exports, "EVMSmartWallet", { enumerable: true, get: function () { return evm_1.EVMSmartWallet; } });
47
+ var svm_1 = require("./svm");
48
+ Object.defineProperty(exports, "SVMVM", { enumerable: true, get: function () { return svm_1.SVMVM; } });
49
+ Object.defineProperty(exports, "SVMChainWallet", { enumerable: true, get: function () { return svm_1.SVMChainWallet; } });
50
+ exports.evm = __importStar(require("./evm"));
51
+ exports.svm = __importStar(require("./svm"));
22
52
  __exportStar(require("./constant"), exports);
23
53
  __exportStar(require("bs58"), exports);
24
54
  __exportStar(require("@solana/web3.js"), exports);
@@ -0,0 +1,52 @@
1
+ import { SavingsManager, Pocket } from "./savings-manager";
2
+ import { Hex, PublicClient, WalletClient } from "viem";
3
+ import { ChainWalletConfig, Balance, TransactionResult } from "../types";
4
+ export declare class EVMSavingsManager extends SavingsManager<Hex, PublicClient, WalletClient> {
5
+ coinType: number;
6
+ derivationPathBase: string;
7
+ private chain;
8
+ private _client?;
9
+ private masterAddress?;
10
+ constructor(mnemonic: string, chain: ChainWalletConfig, walletIndex?: number, masterAddress?: Hex);
11
+ get client(): PublicClient;
12
+ createClient(rpcUrl: string): PublicClient;
13
+ clearClient(): void;
14
+ derivePocket(accountIndex: number): Pocket<Hex>;
15
+ getMainWallet(): {
16
+ privateKey: string;
17
+ address: Hex;
18
+ derivationPath: string;
19
+ };
20
+ getMainWalletAddress(): Hex;
21
+ getPocketBalance(pocketIndex: number, tokens: string[]): Promise<{
22
+ address: Hex | 'native';
23
+ balance: Balance;
24
+ }[]>;
25
+ getTotalTokenBalanceOfAllPockets(tokens: string[], pockets: number[]): Promise<Array<{
26
+ address: Hex | 'native';
27
+ balance: Balance;
28
+ }[]>>;
29
+ transferToPocket(mainWallet: WalletClient, pocketIndex: number, amount: string): Promise<TransactionResult>;
30
+ transferTokenToPocket(mainWallet: WalletClient, tokenAddress: string, pocketIndex: number, amount: bigint): Promise<TransactionResult>;
31
+ accountFromPocketId(pocketIndex: number): {
32
+ address: import("viem").Address;
33
+ nonceManager?: import("viem").NonceManager | undefined;
34
+ sign: (parameters: {
35
+ hash: import("viem").Hash;
36
+ }) => Promise<Hex>;
37
+ signAuthorization: (parameters: import("viem").AuthorizationRequest) => Promise<import("viem/accounts").SignAuthorizationReturnType>;
38
+ signMessage: ({ message }: {
39
+ message: import("viem").SignableMessage;
40
+ }) => Promise<Hex>;
41
+ signTransaction: <serializer extends import("viem").SerializeTransactionFn<import("viem").TransactionSerializable> = import("viem").SerializeTransactionFn<import("viem").TransactionSerializable>, transaction extends Parameters<serializer>[0] = Parameters<serializer>[0]>(transaction: transaction, options?: {
42
+ serializer?: serializer | undefined;
43
+ } | undefined) => Promise<Hex>;
44
+ signTypedData: <const typedData extends import("viem").TypedData | Record<string, unknown>, primaryType extends keyof typedData | "EIP712Domain" = keyof typedData>(parameters: import("viem").TypedDataDefinition<typedData, primaryType>) => Promise<Hex>;
45
+ publicKey: Hex;
46
+ source: "privateKey";
47
+ type: "local";
48
+ };
49
+ verifyPocketAddress(accountIndex: number, storedAddress: string): boolean;
50
+ sendToMainWallet(pocketIndex: number, amount: bigint, token: Hex | "native"): Promise<TransactionResult>;
51
+ dispose(): void;
52
+ }
@@ -0,0 +1,159 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EVMSavingsManager = void 0;
4
+ const savings_manager_1 = require("./savings-manager");
5
+ const viem_1 = require("viem");
6
+ const walletBip32_1 = require("../walletBip32");
7
+ const ethers_1 = require("ethers");
8
+ const evm_1 = require("../evm");
9
+ const validation_1 = require("./validation");
10
+ const accounts_1 = require("viem/accounts");
11
+ class EVMSavingsManager extends savings_manager_1.SavingsManager {
12
+ coinType = 60;
13
+ derivationPathBase = "m/44'/60'/";
14
+ chain;
15
+ _client;
16
+ masterAddress;
17
+ constructor(mnemonic, chain, walletIndex = 0, masterAddress) {
18
+ super(mnemonic, walletIndex);
19
+ validation_1.SavingsValidation.validateChainId(chain.chainId);
20
+ if (masterAddress) {
21
+ validation_1.SavingsValidation.validateAddress(masterAddress, 'Master address');
22
+ }
23
+ this.chain = chain;
24
+ this.masterAddress = masterAddress;
25
+ }
26
+ get client() {
27
+ if (!this._client) {
28
+ this._client = this.createClient(this.chain.rpcUrl);
29
+ }
30
+ return this._client;
31
+ }
32
+ createClient(rpcUrl) {
33
+ return (0, viem_1.createPublicClient)({
34
+ chain: (0, evm_1.fromChainToViemChain)(this.chain),
35
+ transport: (0, viem_1.http)(rpcUrl)
36
+ });
37
+ }
38
+ clearClient() {
39
+ this._client = undefined;
40
+ }
41
+ derivePocket(accountIndex) {
42
+ this.checkNotDisposed();
43
+ validation_1.SavingsValidation.validateAccountIndex(accountIndex);
44
+ const pocketIndex = accountIndex + 1;
45
+ const derivationPath = `${this.derivationPathBase}${pocketIndex}'/0/${this.walletIndex}`;
46
+ const seed = (0, walletBip32_1.mnemonicToSeed)(this.mnemonic);
47
+ const { privateKey } = (0, walletBip32_1.EVMDeriveChildPrivateKey)(seed, this.walletIndex, derivationPath);
48
+ const wallet = new ethers_1.ethers.Wallet(privateKey);
49
+ const pocket = {
50
+ privateKey,
51
+ address: wallet.address,
52
+ derivationPath,
53
+ index: pocketIndex
54
+ };
55
+ this.pockets.set(accountIndex, pocket);
56
+ return pocket;
57
+ }
58
+ getMainWallet() {
59
+ this.checkNotDisposed();
60
+ const derivationPath = `${this.derivationPathBase}0'/0/${this.walletIndex}`;
61
+ const seed = (0, walletBip32_1.mnemonicToSeed)(this.mnemonic);
62
+ const { privateKey } = (0, walletBip32_1.EVMDeriveChildPrivateKey)(seed, this.walletIndex, derivationPath);
63
+ const wallet = new ethers_1.ethers.Wallet(privateKey);
64
+ return {
65
+ privateKey,
66
+ address: wallet.address,
67
+ derivationPath
68
+ };
69
+ }
70
+ getMainWalletAddress() {
71
+ if (this.masterAddress)
72
+ return this.masterAddress;
73
+ return this.getMainWallet().address;
74
+ }
75
+ async getPocketBalance(pocketIndex, tokens) {
76
+ validation_1.SavingsValidation.validateAccountIndex(pocketIndex);
77
+ if (!Array.isArray(tokens)) {
78
+ throw new Error('Tokens must be an array');
79
+ }
80
+ const pocket = this.getPocket(pocketIndex);
81
+ const balances = [];
82
+ const nativeBalance = await (0, evm_1.getNativeBalance)(pocket.address, this.client);
83
+ balances.push({ address: 'native', balance: nativeBalance });
84
+ await Promise.all(tokens.map(async (token) => {
85
+ validation_1.SavingsValidation.validateAddress(token, 'Token address');
86
+ const tokenBalance = await (0, evm_1.getTokenBalance)(token, pocket.address, this.client);
87
+ balances.push({ address: token, balance: tokenBalance });
88
+ }));
89
+ return balances;
90
+ }
91
+ async getTotalTokenBalanceOfAllPockets(tokens, pockets) {
92
+ if (!Array.isArray(tokens) || tokens.length === 0) {
93
+ throw new Error('Tokens array must be non-empty');
94
+ }
95
+ if (!Array.isArray(pockets) || pockets.length === 0) {
96
+ throw new Error('Pockets array must be non-empty');
97
+ }
98
+ tokens.forEach((token, index) => {
99
+ validation_1.SavingsValidation.validateAddress(token, `Token at index ${index}`);
100
+ });
101
+ pockets.forEach((pocket) => {
102
+ validation_1.SavingsValidation.validateAccountIndex(pocket);
103
+ });
104
+ const allBalances = await Promise.all(pockets.map((p) => this.getPocketBalance(p, tokens)));
105
+ return allBalances;
106
+ }
107
+ async transferToPocket(mainWallet, pocketIndex, amount) {
108
+ validation_1.SavingsValidation.validateAccountIndex(pocketIndex);
109
+ validation_1.SavingsValidation.validateAmountString(amount, 'Transfer amount');
110
+ const pocket = this.getPocket(pocketIndex);
111
+ return await (0, evm_1.sendNativeToken)(mainWallet, this.client, pocket.address, amount, 5);
112
+ }
113
+ async transferTokenToPocket(mainWallet, tokenAddress, pocketIndex, amount) {
114
+ validation_1.SavingsValidation.validateAddress(tokenAddress, 'Token address');
115
+ validation_1.SavingsValidation.validateAccountIndex(pocketIndex);
116
+ validation_1.SavingsValidation.validateAmount(amount, 'Transfer amount');
117
+ const pocket = this.getPocket(pocketIndex);
118
+ return await (0, evm_1.sendERC20Token)(mainWallet, this.client, tokenAddress, pocket.address, amount, 5);
119
+ }
120
+ accountFromPocketId(pocketIndex) {
121
+ const pocket = this.getPocket(pocketIndex);
122
+ return (0, accounts_1.privateKeyToAccount)(`0x${pocket.privateKey}`);
123
+ }
124
+ verifyPocketAddress(accountIndex, storedAddress) {
125
+ validation_1.SavingsValidation.validateAccountIndex(accountIndex);
126
+ validation_1.SavingsValidation.validateAddress(storedAddress, 'Stored address');
127
+ const pocket = this.getPocket(accountIndex);
128
+ return pocket.address.toLowerCase() === storedAddress.toLowerCase();
129
+ }
130
+ async sendToMainWallet(pocketIndex, amount, token) {
131
+ validation_1.SavingsValidation.validateAccountIndex(pocketIndex);
132
+ if (typeof amount !== 'bigint' || amount <= 0n) {
133
+ throw new Error(`Amount must be a positive bigint, got: ${amount}`);
134
+ }
135
+ if (token !== 'native') {
136
+ validation_1.SavingsValidation.validateAddress(token, 'Token address');
137
+ }
138
+ const pocket = this.getPocket(pocketIndex);
139
+ const account = this.accountFromPocketId(pocketIndex);
140
+ const mainWalletAddress = this.getMainWalletAddress();
141
+ const walletClient = (0, viem_1.createWalletClient)({
142
+ account,
143
+ transport: (0, viem_1.http)(this.chain.rpcUrl),
144
+ chain: (0, evm_1.fromChainToViemChain)(this.chain)
145
+ });
146
+ if (token === "native") {
147
+ return await (0, evm_1.sendNativeToken)(walletClient, this.client, mainWalletAddress, amount);
148
+ }
149
+ return await (0, evm_1.sendERC20Token)(walletClient, this.client, token, mainWalletAddress, amount);
150
+ }
151
+ dispose() {
152
+ super.dispose();
153
+ this.clearClient();
154
+ if (this.masterAddress) {
155
+ this.masterAddress = undefined;
156
+ }
157
+ }
158
+ }
159
+ exports.EVMSavingsManager = EVMSavingsManager;