@deserialize/multi-vm-wallet 1.3.1 → 1.3.3

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 (98) hide show
  1. package/.claude/settings.local.json +7 -1
  2. package/dist/IChainWallet.d.ts +3 -3
  3. package/dist/constant.js +60 -16
  4. package/dist/constant.js.map +1 -1
  5. package/dist/evm/aa-service/index.d.ts +2 -2
  6. package/dist/evm/aa-service/index.js +1 -3
  7. package/dist/evm/aa-service/index.js.map +1 -1
  8. package/dist/evm/aa-service/lib/kernel-account.d.ts +2 -44
  9. package/dist/evm/aa-service/lib/kernel-account.js +42 -93
  10. package/dist/evm/aa-service/lib/kernel-account.js.map +1 -1
  11. package/dist/evm/aa-service/lib/session-keys.d.ts +14 -17
  12. package/dist/evm/aa-service/lib/session-keys.js +40 -58
  13. package/dist/evm/aa-service/lib/session-keys.js.map +1 -1
  14. package/dist/evm/aa-service/lib/type.d.ts +18 -1
  15. package/dist/evm/aa-service/lib/type.js.map +1 -1
  16. package/dist/evm/aa-service/services/account-abstraction.d.ts +7 -29
  17. package/dist/evm/aa-service/services/account-abstraction.js +12 -68
  18. package/dist/evm/aa-service/services/account-abstraction.js.map +1 -1
  19. package/dist/evm/aa-service/services/bundler.d.ts +4 -1
  20. package/dist/evm/aa-service/services/bundler.js +41 -7
  21. package/dist/evm/aa-service/services/bundler.js.map +1 -1
  22. package/dist/evm/evm.d.ts +164 -14
  23. package/dist/evm/evm.js +259 -80
  24. package/dist/evm/evm.js.map +1 -1
  25. package/dist/evm/smartWallet.d.ts +12 -61
  26. package/dist/evm/smartWallet.js +143 -184
  27. package/dist/evm/smartWallet.js.map +1 -1
  28. package/dist/evm/utils.js +1 -1
  29. package/dist/evm/utils.js.map +1 -1
  30. package/dist/helpers/index.d.ts +6 -1
  31. package/dist/helpers/index.js +116 -0
  32. package/dist/helpers/index.js.map +1 -1
  33. package/dist/privacy/artifact-manager.d.ts +117 -0
  34. package/dist/privacy/artifact-manager.js +251 -0
  35. package/dist/privacy/artifact-manager.js.map +1 -0
  36. package/dist/privacy/broadcaster-client.d.ts +166 -0
  37. package/dist/privacy/broadcaster-client.js +261 -0
  38. package/dist/privacy/broadcaster-client.js.map +1 -0
  39. package/dist/privacy/index.d.ts +34 -0
  40. package/dist/privacy/index.js +56 -0
  41. package/dist/privacy/index.js.map +1 -0
  42. package/dist/privacy/network-config.d.ts +57 -0
  43. package/dist/privacy/network-config.js +118 -0
  44. package/dist/privacy/network-config.js.map +1 -0
  45. package/dist/privacy/poi-helper.d.ts +161 -0
  46. package/dist/privacy/poi-helper.js +249 -0
  47. package/dist/privacy/poi-helper.js.map +1 -0
  48. package/dist/privacy/railgun-engine.d.ts +135 -0
  49. package/dist/privacy/railgun-engine.js +205 -0
  50. package/dist/privacy/railgun-engine.js.map +1 -0
  51. package/dist/privacy/railgun-privacy-wallet.d.ts +288 -0
  52. package/dist/privacy/railgun-privacy-wallet.js +539 -0
  53. package/dist/privacy/railgun-privacy-wallet.js.map +1 -0
  54. package/dist/privacy/types.d.ts +229 -0
  55. package/dist/privacy/types.js +26 -0
  56. package/dist/privacy/types.js.map +1 -0
  57. package/dist/savings/savings-manager.d.ts +126 -0
  58. package/dist/savings/savings-manager.js +234 -0
  59. package/dist/savings/savings-manager.js.map +1 -0
  60. package/dist/savings/smart-savings.d.ts +74 -0
  61. package/dist/savings/smart-savings.js +152 -0
  62. package/dist/savings/smart-savings.js.map +1 -0
  63. package/dist/savings/types.d.ts +125 -0
  64. package/dist/savings/types.js +9 -0
  65. package/dist/savings/types.js.map +1 -0
  66. package/dist/svm/svm.d.ts +19 -3
  67. package/dist/svm/svm.js +29 -17
  68. package/dist/svm/svm.js.map +1 -1
  69. package/dist/svm/utils.d.ts +2 -2
  70. package/dist/svm/utils.js +4 -4
  71. package/dist/svm/utils.js.map +1 -1
  72. package/dist/test.js +81 -22
  73. package/dist/test.js.map +1 -1
  74. package/dist/types.d.ts +14 -16
  75. package/dist/types.js.map +1 -1
  76. package/dist/vm.d.ts +14 -0
  77. package/dist/vm.js.map +1 -1
  78. package/package.json +6 -1
  79. package/utils/IChainWallet.ts +3 -3
  80. package/utils/constant.ts +63 -16
  81. package/utils/evm/aa-service/index.ts +1 -3
  82. package/utils/evm/aa-service/lib/kernel-account.ts +45 -136
  83. package/utils/evm/aa-service/lib/session-keys.ts +58 -60
  84. package/utils/evm/aa-service/lib/type.ts +19 -1
  85. package/utils/evm/aa-service/services/account-abstraction.ts +24 -76
  86. package/utils/evm/aa-service/services/bundler.ts +54 -11
  87. package/utils/evm/evm.ts +313 -110
  88. package/utils/evm/smartWallet.ts +124 -214
  89. package/utils/evm/utils.ts +2 -1
  90. package/utils/helpers/index.ts +138 -1
  91. package/utils/savings/savings-manager.ts +271 -0
  92. package/utils/savings/smart-savings.ts +184 -0
  93. package/utils/savings/types.ts +135 -0
  94. package/utils/svm/svm.ts +34 -25
  95. package/utils/svm/utils.ts +4 -10
  96. package/utils/test.ts +112 -24
  97. package/utils/types.ts +15 -17
  98. package/utils/vm.ts +10 -0
@@ -0,0 +1,271 @@
1
+ /**
2
+ * Savings Manager
3
+ *
4
+ * Core logic for managing BIP-44 derived savings accounts.
5
+ * Provides security-first operations that always derive addresses from account indices.
6
+ *
7
+ * Security Model:
8
+ * - NEVER trust stored addresses without verification
9
+ * - ALWAYS derive addresses from accountIndex for transactions
10
+ * - Provide verification and audit tools for tamper detection
11
+ */
12
+
13
+ import { Hex } from "viem";
14
+ import { EVMVM } from "../evm/evm";
15
+ import { SVMVM } from "../svm/svm";
16
+ import { VM } from "../vm";
17
+ import {
18
+ SavingsAccount,
19
+ AddressVerificationResult,
20
+ SavingsAuditResult,
21
+ TransferToSavingsOptions,
22
+ WithdrawFromSavingsOptions
23
+ } from "./types";
24
+
25
+ // ============================================
26
+ // SavingsManager Class
27
+ // ============================================
28
+
29
+ /**
30
+ * Manages BIP-44 derived savings accounts
31
+ *
32
+ * This class provides:
33
+ * 1. Account derivation from BIP-44 account indices
34
+ * 2. Address verification to prevent database tampering
35
+ * 3. Transaction builders for deposits and withdrawals
36
+ * 4. Batch auditing of stored addresses
37
+ */
38
+ export class SavingsManager {
39
+ private vm: VM<any, any, any>;
40
+
41
+ constructor(vm: VM<any, any, any>) {
42
+ this.vm = vm;
43
+ }
44
+
45
+ /**
46
+ * Create a new savings account by deriving from account index
47
+ *
48
+ * @param accountIndex - BIP-44 account index (1+ for savings, 0 is main wallet)
49
+ * @returns SavingsAccount with derived private key and address
50
+ *
51
+ * @example
52
+ * const savingsAccount = manager.createSavingsAccount(1); // First savings account
53
+ * console.log(savingsAccount.address); // Derived address
54
+ * console.log(savingsAccount.derivationPath); // m/44'/60'/1'/0/0
55
+ */
56
+ createSavingsAccount(accountIndex: number): SavingsAccount {
57
+ if (accountIndex < 0) {
58
+ throw new Error("Account index must be non-negative");
59
+ }
60
+
61
+ const derived = this.vm.deriveSavingsAccount(accountIndex);
62
+
63
+ // For EVM, the address is a string (Hex)
64
+ // For SVM, the address is a PublicKey
65
+ let addressHex: Hex;
66
+ let privateKeyHex: Hex;
67
+
68
+ if (this.vm instanceof EVMVM) {
69
+ addressHex = derived.address as Hex;
70
+ privateKeyHex = (derived.privateKey as string).startsWith('0x')
71
+ ? derived.privateKey as Hex
72
+ : `0x${derived.privateKey}` as Hex;
73
+ } else if (this.vm instanceof SVMVM) {
74
+ // For SVM, convert PublicKey to base58 string
75
+ addressHex = derived.address.toBase58() as Hex;
76
+ // For SVM, convert Keypair secret key to hex
77
+ const keypair = derived.privateKey as any;
78
+ privateKeyHex = `0x${Buffer.from(keypair.secretKey).toString('hex')}` as Hex;
79
+ } else {
80
+ throw new Error("Unsupported VM type");
81
+ }
82
+
83
+ return {
84
+ accountIndex,
85
+ privateKey: privateKeyHex,
86
+ address: addressHex,
87
+ derivationPath: derived.derivationPath
88
+ };
89
+ }
90
+
91
+ /**
92
+ * Verify a stored address matches the derived address for an account index
93
+ *
94
+ * Security: This prevents database tampering attacks where an attacker
95
+ * modifies stored addresses to redirect funds.
96
+ *
97
+ * @param accountIndex - The account index to verify
98
+ * @param storedAddress - The address from storage/database
99
+ * @returns Verification result with validity flag and details
100
+ *
101
+ * @example
102
+ * const result = manager.verifySavingsAddress(1, storedAddress);
103
+ * if (!result.isValid) {
104
+ * console.error("Address mismatch! Possible tampering:", result.error);
105
+ * }
106
+ */
107
+ verifySavingsAddress(accountIndex: number, storedAddress: Hex): AddressVerificationResult {
108
+ try {
109
+ const derived = this.createSavingsAccount(accountIndex);
110
+
111
+ const isValid = derived.address.toLowerCase() === storedAddress.toLowerCase();
112
+
113
+ return {
114
+ accountIndex,
115
+ storedAddress,
116
+ derivedAddress: derived.address,
117
+ isValid,
118
+ error: isValid ? undefined : "Address mismatch - stored address does not match derived address"
119
+ };
120
+ } catch (error: any) {
121
+ return {
122
+ accountIndex,
123
+ storedAddress,
124
+ derivedAddress: "0x0" as Hex,
125
+ isValid: false,
126
+ error: `Verification failed: ${error.message}`
127
+ };
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Audit multiple savings addresses at once
133
+ *
134
+ * Useful for batch verification of all stored savings addresses.
135
+ *
136
+ * @param addresses - Map of accountIndex to stored address
137
+ * @returns Audit result with summary and per-address details
138
+ *
139
+ * @example
140
+ * const addresses = new Map([
141
+ * [1, "0xabc..."],
142
+ * [2, "0xdef..."]
143
+ * ]);
144
+ * const audit = manager.auditSavingsAddresses(addresses);
145
+ * console.log(`Valid: ${audit.valid}/${audit.total}`);
146
+ */
147
+ auditSavingsAddresses(addresses: Map<number, Hex>): SavingsAuditResult {
148
+ const results: AddressVerificationResult[] = [];
149
+
150
+ for (const [accountIndex, storedAddress] of addresses.entries()) {
151
+ const result = this.verifySavingsAddress(accountIndex, storedAddress);
152
+ results.push(result);
153
+ }
154
+
155
+ const valid = results.filter(r => r.isValid).length;
156
+ const invalid = results.filter(r => !r.isValid).length;
157
+
158
+ return {
159
+ total: results.length,
160
+ valid,
161
+ invalid,
162
+ allValid: invalid === 0,
163
+ results,
164
+ timestamp: new Date()
165
+ };
166
+ }
167
+
168
+ /**
169
+ * Build transaction parameters for depositing to savings
170
+ *
171
+ * Security: Always derives the destination address from accountIndex.
172
+ * Optional expectedAddress parameter allows tamper detection.
173
+ *
174
+ * @param accountIndex - Savings account to deposit to
175
+ * @param amount - Amount to transfer (in base units)
176
+ * @param options - Optional security and priority settings
177
+ * @returns Transaction parameters (to, value, data)
178
+ *
179
+ * @example
180
+ * const txParams = manager.buildDepositTransaction(1, parseEther("1.0"), {
181
+ * expectedAddress: storedAddress // Verify it matches derived
182
+ * });
183
+ */
184
+ buildDepositTransaction(
185
+ accountIndex: number,
186
+ amount: bigint,
187
+ options?: TransferToSavingsOptions
188
+ ): { to: Hex; value: bigint; data?: Hex } {
189
+ const savingsAccount = this.createSavingsAccount(accountIndex);
190
+
191
+ // Security check: if expectedAddress provided, verify it matches
192
+ if (options?.expectedAddress) {
193
+ const verification = this.verifySavingsAddress(accountIndex, options.expectedAddress);
194
+ if (!verification.isValid) {
195
+ throw new Error(
196
+ `Security check failed: Expected address ${options.expectedAddress} ` +
197
+ `does not match derived address ${savingsAccount.address}. ` +
198
+ `Possible database tampering detected.`
199
+ );
200
+ }
201
+ }
202
+
203
+ return {
204
+ to: savingsAccount.address,
205
+ value: amount,
206
+ data: undefined // Simple native transfer
207
+ };
208
+ }
209
+
210
+ /**
211
+ * Build transaction parameters for withdrawing from savings
212
+ *
213
+ * Security: Uses the derived private key for signing.
214
+ * Optional expectedAddress parameter verifies the source address.
215
+ *
216
+ * @param accountIndex - Savings account to withdraw from
217
+ * @param to - Destination address
218
+ * @param amount - Amount to transfer (in base units)
219
+ * @param options - Optional security and priority settings
220
+ * @returns Transaction parameters and private key for signing
221
+ *
222
+ * @example
223
+ * const { privateKey, tx } = manager.buildWithdrawalTransaction(
224
+ * 1, destinationAddress, parseEther("0.5")
225
+ * );
226
+ * // Use privateKey to sign the transaction
227
+ */
228
+ buildWithdrawalTransaction(
229
+ accountIndex: number,
230
+ to: Hex,
231
+ amount: bigint,
232
+ options?: WithdrawFromSavingsOptions
233
+ ): { privateKey: Hex; from: Hex; to: Hex; value: bigint; data?: Hex } {
234
+ const savingsAccount = this.createSavingsAccount(accountIndex);
235
+
236
+ // Security check: if expectedAddress provided, verify it matches
237
+ if (options?.expectedAddress) {
238
+ const verification = this.verifySavingsAddress(accountIndex, options.expectedAddress);
239
+ if (!verification.isValid) {
240
+ throw new Error(
241
+ `Security check failed: Expected address ${options.expectedAddress} ` +
242
+ `does not match derived address ${savingsAccount.address}. ` +
243
+ `Possible database tampering detected.`
244
+ );
245
+ }
246
+ }
247
+
248
+ return {
249
+ privateKey: savingsAccount.privateKey,
250
+ from: savingsAccount.address,
251
+ to,
252
+ value: amount,
253
+ data: undefined // Simple native transfer
254
+ };
255
+ }
256
+
257
+ /**
258
+ * Get savings account details without exposing private key
259
+ *
260
+ * @param accountIndex - The account index
261
+ * @returns Public account information (address and derivation path only)
262
+ */
263
+ getSavingsAccountInfo(accountIndex: number): Omit<SavingsAccount, 'privateKey'> {
264
+ const account = this.createSavingsAccount(accountIndex);
265
+ return {
266
+ accountIndex: account.accountIndex,
267
+ address: account.address,
268
+ derivationPath: account.derivationPath
269
+ };
270
+ }
271
+ }
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Smart Savings Manager
3
+ *
4
+ * Handles upgrading savings accounts to EIP-7702 smart accounts.
5
+ * Enables advanced features like locked savings, spend & save, and periodic savings.
6
+ *
7
+ * Architecture:
8
+ * 1. Take a basic SavingsAccount (BIP-44 derived)
9
+ * 2. Create an EVMSmartWallet instance from its private key
10
+ * 3. Initialize with EIP-7702 delegation
11
+ * 4. Return a SmartSavingsAccount with full AA capabilities
12
+ */
13
+
14
+ import { Chain } from "viem/chains";
15
+ import { EVMSmartWallet } from "../evm/smartWallet";
16
+ import { SmartWalletOptions } from "../evm/aa-service";
17
+ import { ChainWalletConfig } from "../types";
18
+ import { SavingsAccount, SmartSavingsAccount } from "./types";
19
+
20
+ // ============================================
21
+ // SmartSavingsManager Class
22
+ // ============================================
23
+
24
+ /**
25
+ * Manages EIP-7702 smart savings accounts
26
+ *
27
+ * This class provides:
28
+ * 1. Upgrade from basic savings account to smart account
29
+ * 2. Full Account Abstraction capabilities
30
+ * 3. Access to Kernel modules (lock, hooks, session keys)
31
+ * 4. Sponsored transactions via paymaster
32
+ */
33
+ export class SmartSavingsManager {
34
+ private chainConfig: ChainWalletConfig;
35
+
36
+ constructor(chainConfig: ChainWalletConfig) {
37
+ this.chainConfig = chainConfig;
38
+
39
+ // Validate AA support
40
+ if (!chainConfig.aaSupport?.enabled) {
41
+ throw new Error(
42
+ "Smart savings requires Account Abstraction (AA) support.\n" +
43
+ "Your chain config must include aaSupport configuration with:\n" +
44
+ "- bundlerUrl\n" +
45
+ "- entryPoints\n" +
46
+ "- kernelImplementations"
47
+ );
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Upgrade a savings account to a smart account with EIP-7702 delegation
53
+ *
54
+ * This enables advanced features:
55
+ * - Lock modules for time-locked savings
56
+ * - Hooks for spend & save
57
+ * - Session keys for periodic savings
58
+ * - Sponsored transactions via paymaster
59
+ *
60
+ * @param savingsAccount - The basic savings account to upgrade
61
+ * @param options - Optional smart wallet configuration
62
+ * @returns SmartSavingsAccount with EVMSmartWallet instance
63
+ *
64
+ * @example
65
+ * const basicSavings = wallet.deriveSavingsAccount(1);
66
+ * const smartSavings = await smartSavingsManager.upgradeSavingsToSmartAccount(basicSavings);
67
+ * await smartSavings.smartWallet.installModule({ ... });
68
+ */
69
+ async upgradeSavingsToSmartAccount(
70
+ savingsAccount: SavingsAccount,
71
+ options?: SmartWalletOptions
72
+ ): Promise<SmartSavingsAccount> {
73
+ // Merge options with chain config
74
+ const mergedOptions: SmartWalletOptions = {
75
+ ...options,
76
+ aaConfig: this.chainConfig.aaSupport,
77
+ bundlerUrl: options?.bundlerUrl || this.chainConfig.aaSupport?.bundlerUrl,
78
+ paymasterUrl: options?.paymasterUrl || this.chainConfig.aaSupport?.paymasterUrl,
79
+ entryPointVersion: options?.entryPointVersion || this.chainConfig.aaSupport?.entryPoints?.[0]?.version
80
+ };
81
+
82
+ // Validate bundlerUrl
83
+ if (!mergedOptions.bundlerUrl) {
84
+ throw new Error(
85
+ "bundlerUrl is required for smart savings.\n" +
86
+ "Provide it via upgradeSavingsToSmartAccount options or chain config."
87
+ );
88
+ }
89
+
90
+ // Create viem chain object
91
+ const chain: Chain = {
92
+ id: this.chainConfig.chainId,
93
+ name: this.chainConfig.name,
94
+ nativeCurrency: {
95
+ name: this.chainConfig.nativeToken.name,
96
+ symbol: this.chainConfig.nativeToken.symbol,
97
+ decimals: this.chainConfig.nativeToken.decimals
98
+ },
99
+ rpcUrls: {
100
+ default: {
101
+ http: [this.chainConfig.rpcUrl]
102
+ }
103
+ },
104
+ blockExplorers: {
105
+ default: {
106
+ name: this.chainConfig.name + " Explorer",
107
+ url: this.chainConfig.explorerUrl
108
+ }
109
+ },
110
+ testnet: this.chainConfig.testnet || false
111
+ };
112
+
113
+ // Create EVMSmartWallet instance from savings account private key
114
+ const smartWallet = new EVMSmartWallet(
115
+ savingsAccount.privateKey,
116
+ chain,
117
+ mergedOptions
118
+ );
119
+
120
+ // Note: Initialization (createAuthorization) is optional
121
+ // User can call smartWallet.initialize() separately if needed
122
+ // For now, we return uninitialized smart wallet
123
+ const isInitialized = false;
124
+
125
+ return {
126
+ ...savingsAccount,
127
+ smartWallet,
128
+ isInitialized
129
+ };
130
+ }
131
+
132
+ /**
133
+ * Upgrade and initialize a savings account in one step
134
+ *
135
+ * This is a convenience method that both upgrades and initializes.
136
+ *
137
+ * @param savingsAccount - The basic savings account to upgrade
138
+ * @param options - Optional smart wallet configuration
139
+ * @returns Initialized SmartSavingsAccount ready for transactions
140
+ *
141
+ * @example
142
+ * const basicSavings = wallet.deriveSavingsAccount(1);
143
+ * const smartSavings = await smartSavingsManager.upgradeSavingsAndInitialize(basicSavings);
144
+ * // smartSavings is now ready for smart transactions
145
+ */
146
+ async upgradeSavingsAndInitialize(
147
+ savingsAccount: SavingsAccount,
148
+ options?: SmartWalletOptions
149
+ ): Promise<SmartSavingsAccount> {
150
+ // First upgrade
151
+ const smartSavings = await this.upgradeSavingsToSmartAccount(savingsAccount, options);
152
+
153
+ // Then initialize
154
+ await smartSavings.smartWallet.initialize();
155
+
156
+ // Update initialization status
157
+ smartSavings.isInitialized = true;
158
+
159
+ return smartSavings;
160
+ }
161
+
162
+ /**
163
+ * Check if a savings account can be upgraded to smart account
164
+ *
165
+ * @returns true if chain supports AA and has required configuration
166
+ */
167
+ canUpgradeToSmartAccount(): boolean {
168
+ return !!(
169
+ this.chainConfig.aaSupport?.enabled &&
170
+ this.chainConfig.aaSupport?.bundlerUrl &&
171
+ this.chainConfig.aaSupport?.entryPoints &&
172
+ this.chainConfig.aaSupport?.entryPoints.length > 0
173
+ );
174
+ }
175
+
176
+ /**
177
+ * Get the chain configuration
178
+ *
179
+ * @returns ChainWalletConfig
180
+ */
181
+ getChainConfig(): ChainWalletConfig {
182
+ return this.chainConfig;
183
+ }
184
+ }
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Savings Pocket Types
3
+ *
4
+ * Type definitions for the savings pocket feature that allows users to create
5
+ * multiple savings accounts derived from their seed phrase using BIP-44 account indices.
6
+ */
7
+
8
+ import { Hex } from "viem";
9
+ import { EVMSmartWallet } from "../evm/smartWallet";
10
+
11
+ /**
12
+ * Savings account derived from BIP-44 account index
13
+ */
14
+ export interface SavingsAccount {
15
+ /** Account index used for derivation (m/44'/60'/accountIndex'/0/0) */
16
+ accountIndex: number;
17
+ /** Derived private key for this savings account */
18
+ privateKey: Hex;
19
+ /** Derived address for this savings account */
20
+ address: Hex;
21
+ /** Full BIP-44 derivation path */
22
+ derivationPath: string;
23
+ }
24
+
25
+ /**
26
+ * Savings account upgraded to EIP-7702 smart account
27
+ */
28
+ export interface SmartSavingsAccount extends SavingsAccount {
29
+ /** Smart wallet instance for advanced features */
30
+ smartWallet: EVMSmartWallet;
31
+ /** Whether the account has been initialized on-chain */
32
+ isInitialized: boolean;
33
+ }
34
+
35
+ /**
36
+ * Options for transferring to savings
37
+ */
38
+ export interface TransferToSavingsOptions {
39
+ /** Expected address for verification (prevents tampering) */
40
+ expectedAddress?: Hex;
41
+ /** Transaction priority for gas estimation */
42
+ priority?: 'low' | 'medium' | 'high';
43
+ /** Whether to use smart account features (requires 7702 upgrade) */
44
+ useSmartAccount?: boolean;
45
+ }
46
+
47
+ /**
48
+ * Options for withdrawing from savings
49
+ */
50
+ export interface WithdrawFromSavingsOptions {
51
+ /** Expected source address for verification */
52
+ expectedAddress?: Hex;
53
+ /** Transaction priority */
54
+ priority?: 'low' | 'medium' | 'high';
55
+ /** Whether to use smart account features */
56
+ useSmartAccount?: boolean;
57
+ }
58
+
59
+ /**
60
+ * Result of address verification
61
+ */
62
+ export interface AddressVerificationResult {
63
+ /** Account index that was verified */
64
+ accountIndex: number;
65
+ /** Stored address that was checked */
66
+ storedAddress: Hex;
67
+ /** Derived address from account index */
68
+ derivedAddress: Hex;
69
+ /** Whether addresses match */
70
+ isValid: boolean;
71
+ /** Error message if invalid */
72
+ error?: string;
73
+ }
74
+
75
+ /**
76
+ * Result of batch address audit
77
+ */
78
+ export interface SavingsAuditResult {
79
+ /** Total number of addresses audited */
80
+ total: number;
81
+ /** Number of valid addresses */
82
+ valid: number;
83
+ /** Number of invalid addresses */
84
+ invalid: number;
85
+ /** Whether all addresses are valid */
86
+ allValid: boolean;
87
+ /** Detailed results per address */
88
+ results: AddressVerificationResult[];
89
+ /** Timestamp of audit */
90
+ timestamp: Date;
91
+ }
92
+
93
+ /**
94
+ * Lock module configuration for locked savings
95
+ */
96
+ export interface LockModuleConfig {
97
+ /** Lock duration in seconds */
98
+ lockDuration: number;
99
+ /** Lock end timestamp (computed) */
100
+ lockedUntil: number;
101
+ /** Whether early withdrawal is allowed with penalty */
102
+ allowEarlyWithdrawal?: boolean;
103
+ /** Penalty percentage for early withdrawal (0-100) */
104
+ earlyWithdrawalPenalty?: number;
105
+ }
106
+
107
+ /**
108
+ * Periodic savings session configuration
109
+ */
110
+ export interface PeriodicSavingsConfig {
111
+ /** Amount to save each period */
112
+ amount: number;
113
+ /** Savings frequency */
114
+ frequency: 'daily' | 'weekly' | 'monthly';
115
+ /** Destination account index */
116
+ savingsAccountIndex: number;
117
+ /** Optional end date for recurring savings */
118
+ endDate?: Date;
119
+ /** Maximum number of executions */
120
+ maxExecutions?: number;
121
+ }
122
+
123
+ /**
124
+ * Spend and save hook configuration
125
+ */
126
+ export interface SpendAndSaveConfig {
127
+ /** Percentage of spending to save (0-100) */
128
+ savePercentage: number;
129
+ /** Destination savings account index */
130
+ savingsAccountIndex: number;
131
+ /** Minimum transaction amount to trigger saving */
132
+ minTransactionAmount?: number;
133
+ /** Maximum amount to save per transaction */
134
+ maxSaveAmount?: number;
135
+ }
package/utils/svm/svm.ts CHANGED
@@ -2,7 +2,7 @@ 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, FeePayerOptions } from "../types";
5
+ import { Balance, ChainWalletConfig, UserTokenBalance, TokenInfo, TransactionResult, NFT } from "../types";
6
6
  import {
7
7
  getSvmNativeBalance,
8
8
  getTokenBalance,
@@ -76,6 +76,33 @@ export class SVMVM extends VM<PublicKey, Keypair, Connection> {
76
76
  const privateKey = SVMDeriveChildPrivateKey(_seed, index, derivationPath);
77
77
  return { privateKey, index };
78
78
  }
79
+
80
+ /**
81
+ * Derive a savings account using BIP-44 account index
82
+ *
83
+ * Uses the pattern: m/44'/501'/accountIndex'/0/0
84
+ * - Main wallet: m/44'/501'/0'/0/0 (account index 0)
85
+ * - Savings 1: m/44'/501'/1'/0/0 (account index 1)
86
+ * - Savings 2: m/44'/501'/2'/0/0 (account index 2)
87
+ *
88
+ * @param accountIndex - The BIP-44 account index (0 for main, 1+ for savings)
89
+ * @returns Object containing privateKey (Keypair), address (PublicKey), and derivation path
90
+ */
91
+ deriveSavingsAccount(accountIndex: number): { privateKey: Keypair; address: PublicKey; derivationPath: string } {
92
+ // Use fixed address index 0 for savings accounts
93
+ // Vary only the account index (3rd position in BIP-44)
94
+ const derivationPath = `m/44'/501'/${accountIndex}'/0/0`;
95
+
96
+ // Derive the keypair using the account index in the path
97
+ const keypair = SVMDeriveChildPrivateKey(this.seed, 0, `m/44'/501'/${accountIndex}'/0/`);
98
+
99
+ return {
100
+ privateKey: keypair,
101
+ address: keypair.publicKey,
102
+ derivationPath
103
+ };
104
+ }
105
+
79
106
  static fromMnemonic(mnemonic: string): VM<PublicKey, Keypair, Connection> {
80
107
  const seed = VM.mnemonicToSeed(mnemonic)
81
108
  return new SVMVM(seed)
@@ -117,56 +144,38 @@ export class SVMChainWallet extends ChainWallet<PublicKey, Keypair, Connection>
117
144
  return nfts
118
145
  }
119
146
 
120
- async transferNative(to: PublicKey, amount: number, feePayerOptions?: FeePayerOptions): Promise<TransactionResult> {
147
+ async transferNative(to: PublicKey, amount: number): Promise<TransactionResult> {
121
148
  // Implement native transfer logic here
122
- let feePayerKeypair: Keypair | undefined;
123
-
124
- if (feePayerOptions) {
125
- // Convert feePayer private key to Keypair
126
- feePayerKeypair = Keypair.fromSecretKey(base58.decode(feePayerOptions.privateKey));
127
- }
128
-
129
149
  const transaction = await getTransferNativeTransaction(
130
150
  this.privateKey,
131
151
  to,
132
152
  amount,
133
- this.connection!,
134
- feePayerKeypair
153
+ this.connection!
135
154
  );
136
155
 
137
156
  const hash = await SVMVM.signAndSendTransaction(
138
157
  transaction,
139
158
  this.connection!,
140
- this.privateKey,
141
- feePayerKeypair ? { feePayerSigner: feePayerKeypair } : undefined
159
+ this.privateKey
142
160
  );
143
161
 
144
162
  return { success: true, hash };
145
163
  }
146
164
 
147
- async transferToken(token: TokenInfo, to: PublicKey, amount: number, feePayerOptions?: FeePayerOptions): Promise<TransactionResult> {
165
+ async transferToken(token: TokenInfo, to: PublicKey, amount: number): Promise<TransactionResult> {
148
166
  // Implement token transfer logic here
149
- let feePayerKeypair: Keypair | undefined;
150
-
151
- if (feePayerOptions) {
152
- // Convert feePayer private key to Keypair
153
- feePayerKeypair = Keypair.fromSecretKey(base58.decode(feePayerOptions.privateKey));
154
- }
155
-
156
167
  const transaction = await getTransferTokenTransaction(
157
168
  this.privateKey,
158
169
  new PublicKey(to),
159
170
  token,
160
171
  amount,
161
- this.connection!,
162
- feePayerKeypair
172
+ this.connection!
163
173
  );
164
174
 
165
175
  const hash = await SVMVM.signAndSendTransaction(
166
176
  transaction,
167
177
  this.connection!,
168
- this.privateKey,
169
- feePayerKeypair ? { feePayerSigner: feePayerKeypair } : undefined
178
+ this.privateKey
170
179
  );
171
180
 
172
181
  return { success: true, hash };