@deserialize/multi-vm-wallet 1.3.2 → 1.3.4

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 (99) hide show
  1. package/.claude/settings.local.json +2 -1
  2. package/dist/IChainWallet.d.ts +2 -0
  3. package/dist/IChainWallet.js.map +1 -1
  4. package/dist/constant.js +60 -16
  5. package/dist/constant.js.map +1 -1
  6. package/dist/evm/aa-service/index.d.ts +1 -1
  7. package/dist/evm/aa-service/index.js +1 -2
  8. package/dist/evm/aa-service/index.js.map +1 -1
  9. package/dist/evm/aa-service/lib/kernel-account.d.ts +1 -1
  10. package/dist/evm/aa-service/lib/kernel-account.js +22 -6
  11. package/dist/evm/aa-service/lib/kernel-account.js.map +1 -1
  12. package/dist/evm/aa-service/lib/session-keys.d.ts +14 -17
  13. package/dist/evm/aa-service/lib/session-keys.js +40 -58
  14. package/dist/evm/aa-service/lib/session-keys.js.map +1 -1
  15. package/dist/evm/aa-service/lib/type.d.ts +2 -1
  16. package/dist/evm/aa-service/lib/type.js.map +1 -1
  17. package/dist/evm/aa-service/services/account-abstraction.d.ts +3 -29
  18. package/dist/evm/aa-service/services/account-abstraction.js +3 -67
  19. package/dist/evm/aa-service/services/account-abstraction.js.map +1 -1
  20. package/dist/evm/aa-service/services/bundler.js +2 -1
  21. package/dist/evm/aa-service/services/bundler.js.map +1 -1
  22. package/dist/evm/evm.d.ts +163 -1
  23. package/dist/evm/evm.js +259 -0
  24. package/dist/evm/evm.js.map +1 -1
  25. package/dist/evm/smartWallet.d.ts +11 -43
  26. package/dist/evm/smartWallet.js +136 -116
  27. package/dist/evm/smartWallet.js.map +1 -1
  28. package/dist/evm/utils.js +0 -1
  29. package/dist/evm/utils.js.map +1 -1
  30. package/dist/index.d.ts +1 -0
  31. package/dist/index.js +1 -0
  32. package/dist/index.js.map +1 -1
  33. package/dist/price.d.ts +2 -0
  34. package/dist/price.js +33 -0
  35. package/dist/price.js.map +1 -0
  36. package/dist/price.types.d.ts +38 -0
  37. package/dist/price.types.js +4 -0
  38. package/dist/price.types.js.map +1 -0
  39. package/dist/privacy/artifact-manager.d.ts +117 -0
  40. package/dist/privacy/artifact-manager.js +251 -0
  41. package/dist/privacy/artifact-manager.js.map +1 -0
  42. package/dist/privacy/broadcaster-client.d.ts +166 -0
  43. package/dist/privacy/broadcaster-client.js +261 -0
  44. package/dist/privacy/broadcaster-client.js.map +1 -0
  45. package/dist/privacy/index.d.ts +34 -0
  46. package/dist/privacy/index.js +56 -0
  47. package/dist/privacy/index.js.map +1 -0
  48. package/dist/privacy/network-config.d.ts +57 -0
  49. package/dist/privacy/network-config.js +118 -0
  50. package/dist/privacy/network-config.js.map +1 -0
  51. package/dist/privacy/poi-helper.d.ts +161 -0
  52. package/dist/privacy/poi-helper.js +249 -0
  53. package/dist/privacy/poi-helper.js.map +1 -0
  54. package/dist/privacy/railgun-engine.d.ts +135 -0
  55. package/dist/privacy/railgun-engine.js +205 -0
  56. package/dist/privacy/railgun-engine.js.map +1 -0
  57. package/dist/privacy/railgun-privacy-wallet.d.ts +288 -0
  58. package/dist/privacy/railgun-privacy-wallet.js +539 -0
  59. package/dist/privacy/railgun-privacy-wallet.js.map +1 -0
  60. package/dist/privacy/types.d.ts +229 -0
  61. package/dist/privacy/types.js +26 -0
  62. package/dist/privacy/types.js.map +1 -0
  63. package/dist/savings/savings-manager.d.ts +126 -0
  64. package/dist/savings/savings-manager.js +234 -0
  65. package/dist/savings/savings-manager.js.map +1 -0
  66. package/dist/savings/smart-savings.d.ts +74 -0
  67. package/dist/savings/smart-savings.js +152 -0
  68. package/dist/savings/smart-savings.js.map +1 -0
  69. package/dist/savings/types.d.ts +125 -0
  70. package/dist/savings/types.js +9 -0
  71. package/dist/savings/types.js.map +1 -0
  72. package/dist/svm/svm.d.ts +18 -0
  73. package/dist/svm/svm.js +35 -0
  74. package/dist/svm/svm.js.map +1 -1
  75. package/dist/test.js +53 -15
  76. package/dist/test.js.map +1 -1
  77. package/dist/vm.d.ts +14 -0
  78. package/dist/vm.js.map +1 -1
  79. package/package.json +2 -1
  80. package/utils/IChainWallet.ts +2 -0
  81. package/utils/constant.ts +63 -16
  82. package/utils/evm/aa-service/index.ts +0 -1
  83. package/utils/evm/aa-service/lib/kernel-account.ts +23 -8
  84. package/utils/evm/aa-service/lib/session-keys.ts +58 -60
  85. package/utils/evm/aa-service/lib/type.ts +2 -1
  86. package/utils/evm/aa-service/services/account-abstraction.ts +10 -76
  87. package/utils/evm/aa-service/services/bundler.ts +2 -1
  88. package/utils/evm/evm.ts +317 -0
  89. package/utils/evm/smartWallet.ts +118 -128
  90. package/utils/evm/utils.ts +1 -1
  91. package/utils/index.ts +1 -0
  92. package/utils/price.ts +37 -0
  93. package/utils/price.types.ts +45 -0
  94. package/utils/savings/savings-manager.ts +271 -0
  95. package/utils/savings/smart-savings.ts +184 -0
  96. package/utils/savings/types.ts +135 -0
  97. package/utils/svm/svm.ts +43 -2
  98. package/utils/test.ts +84 -19
  99. package/utils/vm.ts +12 -1
package/utils/evm/evm.ts CHANGED
@@ -37,6 +37,18 @@ import { EVMTransactionHistoryItem, getEVMTransactionHistory } from "./transacti
37
37
  import { createPublicClient, Hex, http, PublicClient, parseEther, parseUnits, Call } from "viem";
38
38
  import { EVMSmartWallet } from "./smartWallet";
39
39
  import { SmartWalletOptions } from "./aa-service";
40
+ import { SavingsManager } from "../savings/savings-manager";
41
+ import { SmartSavingsManager } from "../savings/smart-savings";
42
+ import {
43
+ SavingsAccount,
44
+ SmartSavingsAccount,
45
+ AddressVerificationResult,
46
+ SavingsAuditResult,
47
+ TransferToSavingsOptions,
48
+ WithdrawFromSavingsOptions
49
+ } from "../savings/types";
50
+ import { fetchPrices } from "../price";
51
+ import { PriceResponse } from "../price.types";
40
52
 
41
53
 
42
54
  interface DebonkQuoteResponse {
@@ -76,6 +88,7 @@ interface DebonkSwapResult {
76
88
 
77
89
 
78
90
  export class EVMVM extends VM<string, string, JsonRpcProvider> {
91
+
79
92
  derivationPath = "m/44'/60'/0'/0/"; // Default EVM derivation path
80
93
 
81
94
  constructor(seed: string) {
@@ -97,6 +110,38 @@ export class EVMVM extends VM<string, string, JsonRpcProvider> {
97
110
  const privateKey = EVMDeriveChildPrivateKey(_seed, index, derivationPath).privateKey;
98
111
  return { privateKey, index };
99
112
  }
113
+
114
+ /**
115
+ * Derive a savings account using BIP-44 account index
116
+ *
117
+ * Uses the pattern: m/44'/60'/accountIndex'/0/0
118
+ * - Main wallet: m/44'/60'/0'/0/0 (account index 0)
119
+ * - Savings 1: m/44'/60'/1'/0/0 (account index 1)
120
+ * - Savings 2: m/44'/60'/2'/0/0 (account index 2)
121
+ *
122
+ * @param accountIndex - The BIP-44 account index (0 for main, 1+ for savings)
123
+ * @returns Object containing privateKey, address, and derivation path
124
+ */
125
+ deriveSavingsAccount(accountIndex: number): { privateKey: string; address: string; derivationPath: string } {
126
+ // Use fixed address index 0 for savings accounts
127
+ // Vary only the account index (3rd position in BIP-44)
128
+ const derivationPath = `m/44'/60'/${accountIndex}'/0/0`;
129
+
130
+ // Derive the full path directly (no additional index appended)
131
+ const result = EVMDeriveChildPrivateKey(this.seed, 0, `m/44'/60'/${accountIndex}'/0/`);
132
+ const privateKey = result.privateKey;
133
+
134
+ // Derive address from private key
135
+ const wallet = new ethers.Wallet(privateKey);
136
+ const address = wallet.address;
137
+
138
+ return {
139
+ privateKey,
140
+ address,
141
+ derivationPath
142
+ };
143
+ }
144
+
100
145
  static fromMnemonic(mnemonic: string): VM<string, string, JsonRpcProvider> {
101
146
  const seed = VM.mnemonicToSeed(mnemonic)
102
147
  return new EVMVM(seed)
@@ -121,6 +166,8 @@ export class EVMChainWallet extends ChainWallet<string, string, JsonRpcProvider>
121
166
  client: PublicClient
122
167
  wallet: Wallet
123
168
  private smartWallet?: EVMSmartWallet
169
+ private savingsManager?: SavingsManager
170
+ private smartSavingsManager?: SmartSavingsManager
124
171
 
125
172
  constructor(config: ChainWalletConfig, privateKey: string, index: number) {
126
173
  super(config, privateKey, index);
@@ -372,6 +419,20 @@ export class EVMChainWallet extends ChainWallet<string, string, JsonRpcProvider>
372
419
  }
373
420
  }
374
421
 
422
+ async getPrices(tokenAddresses: string[]): Promise<PriceResponse> {
423
+ const result = await fetchPrices({
424
+ vm: 'EVM',
425
+ chainId: this.config.chainId,
426
+ tokenAddresses,
427
+ });
428
+
429
+ if (result.error) {
430
+ throw new Error(result.error.message);
431
+ }
432
+
433
+ return result.data as PriceResponse;
434
+ }
435
+
375
436
  // Updated swap method signature to match base class so created another method to use it inside swap
376
437
  async swap(
377
438
  tokenAddress: TokenInfo,
@@ -786,4 +847,260 @@ export class EVMChainWallet extends ChainWallet<string, string, JsonRpcProvider>
786
847
  const signer = this.getWallet()
787
848
  return signer.signMessage(message)
788
849
  }
850
+
851
+ // ============================================
852
+ // Savings Pocket Methods
853
+ // ============================================
854
+
855
+ /**
856
+ * Get or create the SavingsManager instance (lazy initialization)
857
+ * @private
858
+ */
859
+ private getSavingsManager(): SavingsManager {
860
+ if (!this.savingsManager) {
861
+ // Create a VM instance from the current wallet's seed
862
+ // We need to get the seed from the privateKey
863
+ // For now, we'll create an EVMVM from the wallet
864
+ // Note: This requires access to the seed, which we'll need to handle
865
+ throw new Error(
866
+ "SavingsManager requires access to the seed phrase. " +
867
+ "Please initialize the wallet with a seed phrase or mnemonic to use savings features."
868
+ );
869
+ }
870
+ return this.savingsManager;
871
+ }
872
+
873
+ /**
874
+ * Initialize savings functionality with a seed phrase
875
+ *
876
+ * This must be called before using any savings methods.
877
+ * The seed is used to derive savings accounts using BIP-44.
878
+ *
879
+ * @param seed - The wallet seed (hex string)
880
+ *
881
+ * @example
882
+ * const seed = VM.mnemonicToSeed(mnemonic);
883
+ * wallet.initializeSavings(seed);
884
+ */
885
+ initializeSavings(seed: string): void {
886
+ const vm = new EVMVM(seed);
887
+ this.savingsManager = new SavingsManager(vm);
888
+ }
889
+
890
+ /**
891
+ * Derive a new savings account from BIP-44 account index
892
+ *
893
+ * @param accountIndex - The BIP-44 account index (1+ for savings, 0 is main wallet)
894
+ * @returns SavingsAccount with derived address and private key
895
+ *
896
+ * @example
897
+ * const savingsAccount1 = wallet.deriveSavingsAccount(1); // m/44'/60'/1'/0/0
898
+ * const savingsAccount2 = wallet.deriveSavingsAccount(2); // m/44'/60'/2'/0/0
899
+ */
900
+ deriveSavingsAccount(accountIndex: number): SavingsAccount {
901
+ return this.getSavingsManager().createSavingsAccount(accountIndex);
902
+ }
903
+
904
+ /**
905
+ * Transfer native tokens to a savings account
906
+ *
907
+ * Security: Always derives the destination address from accountIndex.
908
+ *
909
+ * @param accountIndex - Savings account index to deposit to
910
+ * @param amount - Amount in ether units (e.g., "1.5" for 1.5 ETH)
911
+ * @param options - Optional security and priority settings
912
+ * @returns Transaction result
913
+ *
914
+ * @example
915
+ * const result = await wallet.transferToSavings(1, "1.5"); // Send 1.5 ETH to savings account 1
916
+ */
917
+ async transferToSavings(
918
+ accountIndex: number,
919
+ amount: string,
920
+ options?: TransferToSavingsOptions
921
+ ): Promise<TransactionResult> {
922
+ const manager = this.getSavingsManager();
923
+
924
+ // Build transaction using derived address
925
+ const amountWei = parseEther(amount);
926
+ const txParams = manager.buildDepositTransaction(accountIndex, amountWei, options);
927
+
928
+ // Execute using existing transferNative method
929
+ return await this.transferNative(txParams.to, Number(amount));
930
+ }
931
+
932
+ /**
933
+ * Withdraw native tokens from a savings account
934
+ *
935
+ * Security: Uses the derived private key for signing.
936
+ *
937
+ * @param accountIndex - Savings account index to withdraw from
938
+ * @param to - Destination address
939
+ * @param amount - Amount in ether units (e.g., "0.5" for 0.5 ETH)
940
+ * @param options - Optional security and priority settings
941
+ * @returns Transaction result
942
+ *
943
+ * @example
944
+ * const result = await wallet.withdrawFromSavings(1, destinationAddress, "0.5");
945
+ */
946
+ async withdrawFromSavings(
947
+ accountIndex: number,
948
+ to: string,
949
+ amount: string,
950
+ options?: WithdrawFromSavingsOptions
951
+ ): Promise<TransactionResult> {
952
+ const manager = this.getSavingsManager();
953
+
954
+ // Build withdrawal transaction
955
+ const amountWei = parseEther(amount);
956
+ const withdrawalParams = manager.buildWithdrawalTransaction(
957
+ accountIndex,
958
+ to as Hex,
959
+ amountWei,
960
+ options
961
+ );
962
+
963
+ // Create a temporary wallet with the savings account private key
964
+ const savingsWallet = new Wallet(withdrawalParams.privateKey, this.connection);
965
+
966
+ // Send transaction using the savings wallet
967
+ const tx = await savingsWallet.sendTransaction({
968
+ to: withdrawalParams.to,
969
+ value: withdrawalParams.value
970
+ });
971
+
972
+ const receipt = await tx.wait(this.config.confirmationNo || 1);
973
+
974
+ return {
975
+ success: receipt?.status === 1,
976
+ hash: receipt?.hash || tx.hash
977
+ };
978
+ }
979
+
980
+ /**
981
+ * Verify a stored savings address matches the derived address
982
+ *
983
+ * Security: Prevents database tampering attacks.
984
+ *
985
+ * @param accountIndex - The account index to verify
986
+ * @param storedAddress - The address from storage/database
987
+ * @returns Verification result
988
+ *
989
+ * @example
990
+ * const result = wallet.verifySavingsAddress(1, storedAddress);
991
+ * if (!result.isValid) {
992
+ * console.error("Security alert: Address tampering detected!");
993
+ * }
994
+ */
995
+ verifySavingsAddress(accountIndex: number, storedAddress: Hex): AddressVerificationResult {
996
+ return this.getSavingsManager().verifySavingsAddress(accountIndex, storedAddress);
997
+ }
998
+
999
+ /**
1000
+ * Audit multiple savings addresses at once
1001
+ *
1002
+ * @param addresses - Map of accountIndex to stored address
1003
+ * @returns Audit result with summary and details
1004
+ *
1005
+ * @example
1006
+ * const addresses = new Map([[1, "0xabc..."], [2, "0xdef..."]]);
1007
+ * const audit = wallet.auditSavingsAddresses(addresses);
1008
+ * console.log(`Valid: ${audit.valid}/${audit.total}`);
1009
+ */
1010
+ auditSavingsAddresses(addresses: Map<number, Hex>): SavingsAuditResult {
1011
+ return this.getSavingsManager().auditSavingsAddresses(addresses);
1012
+ }
1013
+
1014
+ /**
1015
+ * Get savings account information without exposing private key
1016
+ *
1017
+ * @param accountIndex - The account index
1018
+ * @returns Public account information (address and derivation path)
1019
+ *
1020
+ * @example
1021
+ * const info = wallet.getSavingsAccountInfo(1);
1022
+ * console.log(`Address: ${info.address}`);
1023
+ * console.log(`Path: ${info.derivationPath}`); // m/44'/60'/1'/0/0
1024
+ */
1025
+ getSavingsAccountInfo(accountIndex: number): Omit<SavingsAccount, 'privateKey'> {
1026
+ return this.getSavingsManager().getSavingsAccountInfo(accountIndex);
1027
+ }
1028
+
1029
+ // ============================================
1030
+ // Smart Savings Methods (EIP-7702)
1031
+ // ============================================
1032
+
1033
+ /**
1034
+ * Get or create the SmartSavingsManager instance (lazy initialization)
1035
+ * @private
1036
+ */
1037
+ private getSmartSavingsManager(): SmartSavingsManager {
1038
+ if (!this.smartSavingsManager) {
1039
+ this.smartSavingsManager = new SmartSavingsManager(this.config);
1040
+ }
1041
+ return this.smartSavingsManager;
1042
+ }
1043
+
1044
+ /**
1045
+ * Upgrade a savings account to a smart account with EIP-7702 delegation
1046
+ *
1047
+ * This enables advanced features:
1048
+ * - Lock modules for time-locked savings
1049
+ * - Hooks for spend & save
1050
+ * - Session keys for periodic savings
1051
+ * - Sponsored transactions via paymaster
1052
+ *
1053
+ * @param accountIndex - The savings account index to upgrade
1054
+ * @param options - Optional smart wallet configuration
1055
+ * @param autoInitialize - Whether to initialize the smart wallet (default: false)
1056
+ * @returns SmartSavingsAccount with EVMSmartWallet instance
1057
+ *
1058
+ * @example
1059
+ * // Upgrade without initialization
1060
+ * const smartSavings = await wallet.upgradeSavingsToSmartAccount(1);
1061
+ * await smartSavings.smartWallet.initialize(); // Initialize separately
1062
+ *
1063
+ * @example
1064
+ * // Upgrade and initialize in one step
1065
+ * const smartSavings = await wallet.upgradeSavingsToSmartAccount(1, {}, true);
1066
+ * // Ready to use immediately
1067
+ */
1068
+ async upgradeSavingsToSmartAccount(
1069
+ accountIndex: number,
1070
+ options?: SmartWalletOptions,
1071
+ autoInitialize: boolean = false
1072
+ ): Promise<SmartSavingsAccount> {
1073
+ const manager = this.getSmartSavingsManager();
1074
+
1075
+ // First derive the basic savings account
1076
+ const basicSavings = this.deriveSavingsAccount(accountIndex);
1077
+
1078
+ // Then upgrade to smart account
1079
+ if (autoInitialize) {
1080
+ return await manager.upgradeSavingsAndInitialize(basicSavings, options);
1081
+ } else {
1082
+ return await manager.upgradeSavingsToSmartAccount(basicSavings, options);
1083
+ }
1084
+ }
1085
+
1086
+ /**
1087
+ * Check if smart savings is supported on this chain
1088
+ *
1089
+ * @returns true if chain supports Account Abstraction
1090
+ *
1091
+ * @example
1092
+ * if (wallet.isSmartSavingsSupported()) {
1093
+ * const smartSavings = await wallet.upgradeSavingsToSmartAccount(1);
1094
+ * } else {
1095
+ * console.log("This chain doesn't support smart savings");
1096
+ * }
1097
+ */
1098
+ isSmartSavingsSupported(): boolean {
1099
+ try {
1100
+ const manager = this.getSmartSavingsManager();
1101
+ return manager.canUpgradeToSmartAccount();
1102
+ } catch (error) {
1103
+ return false;
1104
+ }
1105
+ }
789
1106
  }
@@ -54,12 +54,11 @@ import type { SessionKeyPermission } from "./aa-service/lib/kernel-modules";
54
54
  * - Account recovery
55
55
  */
56
56
  export class EVMSmartWallet {
57
- private aaService: AccountAbstractionService | null = null;
57
+ aaService: AccountAbstractionService | null = null;
58
58
  private kernelAccount: KernelAccountInstance | null = null;
59
59
  private ownerAccount: PrivateKeyAccount;
60
60
  private chain: Chain;
61
61
  private options: SmartWalletOptions;
62
- private sessionAccount: any = null;
63
62
  private paymasterConfig: PaymasterConfig | null = null;
64
63
 
65
64
  constructor(
@@ -95,7 +94,7 @@ export class EVMSmartWallet {
95
94
  try {
96
95
  // Initialize AA service singleton with AA config
97
96
  this.aaService = AccountAbstractionService.getInstance({
98
- bundlerProvider: 'custom',
97
+ bundlerProvider: 'pimlico',
99
98
  customBundlerUrl: this.options.bundlerUrl!,
100
99
  aaConfig: this.options.aaConfig
101
100
  });
@@ -202,35 +201,67 @@ export class EVMSmartWallet {
202
201
  async sendTransaction(
203
202
  to: Hex,
204
203
  value: bigint = 0n,
205
- data: Hex = '0x'
204
+ data: Hex = '0x',
205
+ options?: { sessionAccount: Omit<KernelAccountInstance, 'owner' | 'entryPoint' | 'chain'> }
206
206
  ): Promise<SmartWalletTransactionResult> {
207
207
  if (!this.kernelAccount || !this.aaService) {
208
208
  throw new SmartWalletError('Smart wallet not initialized', 'NOT_INITIALIZED');
209
209
  }
210
210
 
211
211
  try {
212
- // Use session account if available, otherwise use kernel account
213
- const account = this.sessionAccount || this.kernelAccount;
214
-
215
- const userOpHash = await this.aaService.sendTransaction({
216
- account,
217
- to,
218
- value,
219
- data
220
- });
221
-
222
- // Wait for receipt
223
- const receipt = await this.aaService.waitForReceipt({
224
- userOpHash,
225
- chain: this.chain
226
- });
227
-
228
- return {
229
- success: true,
230
- userOpHash,
231
- transactionHash: receipt.transactionHash
232
- };
212
+ // Use session account if available and requested
213
+ if (options?.sessionAccount) {
214
+ // Session keys use kernel account client, not bundler client
215
+ const { createSessionKeyClient } = await import('./aa-service/lib/session-keys');
216
+
217
+ const kernelClient = createSessionKeyClient({
218
+ account: options.sessionAccount.account,
219
+ chain: this.chain,
220
+ bundlerUrl: this.options.bundlerUrl!,
221
+ });
222
+
223
+ // Use kernel client to send transaction
224
+ const userOpHash = await kernelClient.sendUserOperation({
225
+ callData: await options.sessionAccount.account.encodeCalls([{
226
+ to,
227
+ value,
228
+ data
229
+ }])
230
+ });
231
+
232
+ // Wait for receipt
233
+ const receipt = await kernelClient.waitForUserOperationReceipt({
234
+ hash: userOpHash
235
+ });
236
+
237
+ return {
238
+ success: true,
239
+ userOpHash,
240
+ transactionHash: receipt.receipt.transactionHash
241
+ };
242
+ } else {
243
+ // Use regular kernel account with AA service
244
+ const userOpHash = await this.aaService.sendTransaction({
245
+ account: this.kernelAccount,
246
+ to,
247
+ value,
248
+ data
249
+ });
250
+
251
+ // Wait for receipt
252
+ const receipt = await this.aaService.waitForReceipt({
253
+ userOpHash,
254
+ chain: this.chain
255
+ });
256
+
257
+ return {
258
+ success: true,
259
+ userOpHash,
260
+ transactionHash: receipt.transactionHash
261
+ };
262
+ }
233
263
  } catch (error) {
264
+ console.log('error: ', error);
234
265
  const errorMsg = error instanceof Error ? error.message : 'Unknown error';
235
266
  return {
236
267
  success: false,
@@ -254,7 +285,7 @@ export class EVMSmartWallet {
254
285
  * { to: usdcAddress, value: 0n, data: transferCalldata }
255
286
  * ]);
256
287
  */
257
- async sendBatchTransaction(calls: Call[]): Promise<SmartWalletTransactionResult> {
288
+ async sendBatchTransaction(calls: Call[], options?: { sessionAccount: KernelAccountInstance }): Promise<SmartWalletTransactionResult> {
258
289
  if (!this.kernelAccount || !this.aaService) {
259
290
  throw new SmartWalletError('Smart wallet not initialized', 'NOT_INITIALIZED');
260
291
  }
@@ -264,32 +295,65 @@ export class EVMSmartWallet {
264
295
  }
265
296
 
266
297
  try {
267
- // Convert to AA service Call format
268
- const aaCalls: AACall[] = calls.map(call => ({
298
+ // Convert to proper Call format
299
+ const normalizedCalls = calls.map(call => ({
269
300
  to: call.to,
270
- value: call.value,
271
- data: call.data
301
+ value: call.value ?? 0n,
302
+ data: call.data ?? '0x' as Hex
272
303
  }));
273
304
 
274
- // Use session account if available, otherwise use kernel account
275
- const account = this.sessionAccount || this.kernelAccount;
276
-
277
- const userOpHash = await this.aaService.sendBatchTransaction({
278
- account,
279
- calls: aaCalls
280
- });
281
-
282
- // Wait for receipt
283
- const receipt = await this.aaService.waitForReceipt({
284
- userOpHash,
285
- chain: this.chain
286
- });
287
-
288
- return {
289
- success: true,
290
- userOpHash,
291
- transactionHash: receipt.transactionHash
292
- };
305
+ // Use session account if available
306
+ if (options?.sessionAccount) {
307
+ // Session keys use kernel account client
308
+ const { createSessionKeyClient } = await import('./aa-service/lib/session-keys');
309
+
310
+ const kernelClient = createSessionKeyClient({
311
+ account: options.sessionAccount.account,
312
+ chain: this.chain,
313
+ bundlerUrl: this.options.bundlerUrl!,
314
+ entryPoint: options.sessionAccount.entryPoint
315
+ });
316
+
317
+ // Use kernel client to send batch transaction
318
+ const userOpHash = await kernelClient.sendUserOperation({
319
+ callData: await options.sessionAccount.account.encodeCalls(normalizedCalls)
320
+ });
321
+
322
+ // Wait for receipt
323
+ const receipt = await kernelClient.waitForUserOperationReceipt({
324
+ hash: userOpHash
325
+ });
326
+
327
+ return {
328
+ success: true,
329
+ userOpHash,
330
+ transactionHash: receipt.receipt.transactionHash
331
+ };
332
+ } else {
333
+ // Use regular kernel account with AA service
334
+ const aaCalls: AACall[] = normalizedCalls.map(call => ({
335
+ to: call.to,
336
+ value: call.value,
337
+ data: call.data
338
+ }));
339
+
340
+ const userOpHash = await this.aaService.sendBatchTransaction({
341
+ account: this.kernelAccount,
342
+ calls: aaCalls
343
+ });
344
+
345
+ // Wait for receipt
346
+ const receipt = await this.aaService.waitForReceipt({
347
+ userOpHash,
348
+ chain: this.chain
349
+ });
350
+
351
+ return {
352
+ success: true,
353
+ userOpHash,
354
+ transactionHash: receipt.transactionHash
355
+ };
356
+ }
293
357
  } catch (error) {
294
358
  const errorMsg = error instanceof Error ? error.message : 'Unknown error';
295
359
  return {
@@ -336,27 +400,7 @@ export class EVMSmartWallet {
336
400
  }
337
401
  }
338
402
 
339
- /**
340
- * Recreate session key from stored private key
341
- *
342
- * @param privateKey - Session key private key
343
- * @returns Session key info
344
- *
345
- * @example
346
- * const sessionKey = await smartWallet.recreateSessionKey(storedPrivateKey);
347
- */
348
- async recreateSessionKey(privateKey: Hex): Promise<SessionKeyInfo> {
349
- if (!this.aaService) {
350
- throw new SmartWalletError('Smart wallet not initialized', 'NOT_INITIALIZED');
351
- }
352
- try {
353
- return await this.aaService.recreateSessionKey(privateKey);
354
- } catch (error) {
355
- throw new SessionKeyError(
356
- `Failed to recreate session key: ${error instanceof Error ? error.message : 'Unknown error'}`
357
- );
358
- }
359
- }
403
+
360
404
 
361
405
  /**
362
406
  * Create session key approval (Owner side)
@@ -380,6 +424,7 @@ export class EVMSmartWallet {
380
424
  try {
381
425
  return await this.aaService.createSessionKeyApproval({
382
426
  sessionKeyAddress: options.sessionKeyAddress,
427
+ sessionKeyPrivateKey: options.sessionKeyPrivateKey,
383
428
  owner: this.ownerAccount,
384
429
  chain: this.chain,
385
430
  entryPointVersion: this.options.entryPointVersion,
@@ -393,52 +438,6 @@ export class EVMSmartWallet {
393
438
  }
394
439
  }
395
440
 
396
- /**
397
- * Use session key for transactions (Agent side)
398
- * Agent deserializes the approval and can send transactions with session key
399
- *
400
- * @param options - Session key usage options with approval and signer
401
- *
402
- * @example
403
- * const sessionKey = await smartWallet.recreateSessionKey(privateKey);
404
- * await smartWallet.useSessionKey({
405
- * approval,
406
- * sessionKeySigner: sessionKey.signer
407
- * });
408
- * // Now can send transactions with session key permissions
409
- */
410
- async useSessionKey(options: SessionKeyUsageOptions): Promise<void> {
411
- if (!this.aaService) {
412
- throw new SmartWalletError('Smart wallet not initialized', 'NOT_INITIALIZED');
413
- }
414
- try {
415
- this.sessionAccount = await this.aaService.deserializeSessionKey({
416
- approval: options.approval,
417
- sessionKeySigner: options.sessionKeySigner,
418
- chain: this.chain,
419
- entryPointVersion: this.options.entryPointVersion
420
- });
421
- } catch (error) {
422
- throw new SessionKeyError(
423
- `Failed to use session key: ${error instanceof Error ? error.message : 'Unknown error'}`
424
- );
425
- }
426
- }
427
-
428
- /**
429
- * Clear session key (revert to owner account)
430
- */
431
- clearSessionKey(): void {
432
- this.sessionAccount = null;
433
- }
434
-
435
- /**
436
- * Check if using session key
437
- */
438
- isUsingSessionKey(): boolean {
439
- return this.sessionAccount !== null;
440
- }
441
-
442
441
  /**
443
442
  * Create USDC transfer permission
444
443
  *
@@ -446,11 +445,11 @@ export class EVMSmartWallet {
446
445
  * @param maxAmount - Maximum USDC amount (in USDC units, e.g., "10" for 10 USDC)
447
446
  * @returns Permission rule
448
447
  */
449
- createUSDCPermission(usdcAddress: Hex, maxAmount: string): SessionKeyPermissionRule {
448
+ createUSDCPermission(usdcAddress: Hex, maxAmount: string, destinationAddress: Hex): SessionKeyPermissionRule {
450
449
  if (!this.aaService) {
451
450
  throw new SmartWalletError('Smart wallet not initialized', 'NOT_INITIALIZED');
452
451
  }
453
- return this.aaService.createUSDCTransferPermission(usdcAddress, maxAmount);
452
+ return this.aaService.createUSDCTransferPermission(usdcAddress, maxAmount, destinationAddress);
454
453
  }
455
454
 
456
455
  /**
@@ -706,14 +705,5 @@ export class EVMSmartWallet {
706
705
  return this.aaService.getBundlerInfo(this.chain);
707
706
  }
708
707
 
709
- /**
710
- * Clear all caches
711
- */
712
- clearCache(): void {
713
- if (this.aaService) {
714
- this.aaService.clearCache();
715
- }
716
- this.kernelAccount = null;
717
- this.sessionAccount = null;
718
- }
708
+
719
709
  }
@@ -641,7 +641,7 @@ export const safeApprove = async (
641
641
 
642
642
  export const discoverTokens = async (wallet: string, chain: ChainWalletConfig): Promise<UserTokenBalance<string>[]> => {
643
643
  const balances = await HelperAPI.getUserToken(wallet, chain.vmType ?? "EVM", chain.chainId)
644
- console.log('balances: ', JSON.stringify(balances));
644
+
645
645
 
646
646
 
647
647
  const formatBalances: UserTokenBalance<string>[] = balances.data.map((token: any) => {