@deserialize/multi-vm-wallet 1.5.2 → 1.5.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.
package/utils/evm/evm.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  */
6
6
 
7
7
  import { EntropyToMnemonic, EVMDeriveChildPrivateKey } from "../walletBip32";
8
- import { ChainWallet } from "../IChainWallet";
8
+ import { ChainAddress, ChainWallet } from "../IChainWallet";
9
9
  import { Balance, ChainWalletConfig, NFTInfo, UserTokenBalance, TokenInfo, TransactionResult, NFT, DiscoveredWallet, WalletDiscoveryOptions, WalletDiscoveryResult, PocketDiscoveryOptions } from "../types";
10
10
  import { VM } from "../vm";
11
11
  import { VMValidation, sanitizeError, logSafeError } from "../vm-validation";
@@ -50,6 +50,76 @@ import { Account, generatePrivateKey, privateKeyToAccount } from "viem/accounts"
50
50
  // import { extendWalletClientWithSavings } from "../savings";
51
51
  // import { SavingsManager } from "../savings/saving-actions";
52
52
 
53
+ const createEvmPublicClient = (config: ChainWalletConfig): PublicClient =>
54
+ createPublicClient({
55
+ chain: fromChainToViemChain(config),
56
+ transport: http(config.rpcUrl),
57
+ });
58
+
59
+ const createEvmWalletClient = (config: ChainWalletConfig, account: Account): WalletClient =>
60
+ createWalletClient({
61
+ account,
62
+ chain: fromChainToViemChain(config),
63
+ transport: http(config.rpcUrl),
64
+ });
65
+
66
+ const getEvmTransactionHistorySafe = async (
67
+ connection: PublicClient,
68
+ address: string
69
+ ): Promise<EVMTransactionHistoryItem[]> => {
70
+ try {
71
+ return await getEVMTransactionHistory(connection, address as Hex);
72
+ } catch {
73
+ return [];
74
+ }
75
+ };
76
+
77
+ const getEvmPrices = async (
78
+ config: ChainWalletConfig,
79
+ tokenAddresses: string[]
80
+ ): Promise<PriceResponse> => {
81
+ const result = await fetchPrices({
82
+ vm: 'EVM',
83
+ chainId: config.chainId,
84
+ tokenAddresses,
85
+ });
86
+
87
+ if (result.error) {
88
+ throw new Error(result.error.message);
89
+ }
90
+
91
+ return result.data as PriceResponse;
92
+ };
93
+
94
+ const getEvmNativeBalance = async (
95
+ address: string,
96
+ connection: PublicClient
97
+ ): Promise<Balance> => {
98
+ return await EVMVM.getNativeBalance(address, connection);
99
+ };
100
+
101
+ const getEvmTokenBalance = async (
102
+ address: string,
103
+ tokenAddress: string,
104
+ connection: PublicClient
105
+ ): Promise<Balance> => {
106
+ return await EVMVM.getTokenBalance(address, tokenAddress, connection);
107
+ };
108
+
109
+ const discoverEvmTokens = async (
110
+ address: string,
111
+ config: ChainWalletConfig
112
+ ): Promise<UserTokenBalance<string>[]> => {
113
+ return await discoverTokens(address, config);
114
+ };
115
+
116
+ const discoverEvmNFTs = async (
117
+ address: string,
118
+ config: ChainWalletConfig
119
+ ): Promise<NFT[]> => {
120
+ return await discoverNFTs(address, config);
121
+ };
122
+
53
123
 
54
124
  interface DebonkQuoteResponse {
55
125
  tokenA: string;
@@ -202,7 +272,8 @@ export class EVMVM extends VM<string, string, PublicClient> {
202
272
  }
203
273
 
204
274
  static convertFromEntropyToPrivateKey = (entropy: string): string => {
205
- return toHex(entropy)
275
+ const p = ethers.id(entropy)
276
+ return p
206
277
  }
207
278
 
208
279
  /**
@@ -687,6 +758,41 @@ export class EVMVM extends VM<string, string, PublicClient> {
687
758
 
688
759
  }
689
760
 
761
+ export class EVMChainAddress extends ChainAddress<string, PublicClient> {
762
+ constructor(config: ChainWalletConfig, address: string, index?: number) {
763
+ const connection = createEvmPublicClient(config);
764
+ super(config, address, index);
765
+ this.connection = connection;
766
+ }
767
+
768
+ async getNativeBalance(): Promise<Balance> {
769
+ return await getEvmNativeBalance(this.address, this.connection!);
770
+ }
771
+
772
+ async getTokenBalance(tokenAddress: string): Promise<Balance> {
773
+ return await getEvmTokenBalance(this.address, tokenAddress, this.connection!);
774
+ }
775
+
776
+ async discoverToken(): Promise<UserTokenBalance<string>[]> {
777
+ return await discoverEvmTokens(this.address, this.config);
778
+ }
779
+
780
+ async discoverNFT(): Promise<NFT[]> {
781
+ return await discoverEvmNFTs(this.address, this.config);
782
+ }
783
+
784
+ async getTransactionHistory(): Promise<EVMTransactionHistoryItem[]> {
785
+ return await getEvmTransactionHistorySafe(this.connection!, this.address);
786
+ }
787
+
788
+ async getPrices(tokenAddresses: string[]): Promise<PriceResponse> {
789
+ return await getEvmPrices(this.config, tokenAddresses);
790
+ }
791
+
792
+
793
+ }
794
+
795
+
690
796
  export class EVMChainWallet extends ChainWallet<string, string, PublicClient> {
691
797
  wallet: WalletClient
692
798
  private smartWallet?: EVMSmartWallet
@@ -695,21 +801,17 @@ export class EVMChainWallet extends ChainWallet<string, string, PublicClient> {
695
801
 
696
802
  constructor(config: ChainWalletConfig, privateKey: string, index: number) {
697
803
  privateKey = privateKey.startsWith('0x') ? privateKey : `0x${privateKey}`
698
- super(config, privateKey, index);
699
- this.connection = createPublicClient(
700
- {
701
- chain: fromChainToViemChain(config),
702
- transport: http(config.rpcUrl)
703
- },
704
- )
804
+ const connection = createEvmPublicClient(config);
705
805
  const account = privateKeyToAccount(privateKey as Hex)
706
- this.wallet = createWalletClient({
707
- account,
708
- chain: fromChainToViemChain(config),
709
- transport: http(config.rpcUrl)
710
- })
711
- this.address = account.address
806
+ const wallet = createEvmWalletClient(config, account);
807
+ const address = account.address
808
+ super(config, address, privateKey, index);
809
+
810
+
712
811
  this.privateKey = privateKey;
812
+ this.wallet = wallet;
813
+ this.connection = connection;
814
+ this.address = address
713
815
  }
714
816
 
715
817
  // ============================================
@@ -887,12 +989,12 @@ export class EVMChainWallet extends ChainWallet<string, string, PublicClient> {
887
989
 
888
990
  async getNativeBalance(): Promise<Balance> {
889
991
  // Implement native balance retrieval logic here
890
- return await EVMVM.getNativeBalance(this.address, this.connection!)
992
+ return await getEvmNativeBalance(this.address, this.connection!);
891
993
  }
892
994
 
893
995
  async getTokenBalance(tokenAddress: string): Promise<Balance> {
894
996
  // Implement token balance retrieval logic here
895
- return await EVMVM.getTokenBalance(this.address, tokenAddress, this.connection!)
997
+ return await getEvmTokenBalance(this.address, tokenAddress, this.connection!);
896
998
  }
897
999
 
898
1000
  async getTokenInfo(tokenAddress: string) {
@@ -901,12 +1003,12 @@ export class EVMChainWallet extends ChainWallet<string, string, PublicClient> {
901
1003
 
902
1004
  async discoverToken(): Promise<UserTokenBalance<string>[]> {
903
1005
  // Implement token discovery logic here
904
- return await discoverTokens(this.address, this.config)
1006
+ return await discoverEvmTokens(this.address, this.config);
905
1007
  }
906
1008
 
907
1009
  async discoverNFT(): Promise<NFT[]> {
908
1010
  // Implement NFT discovery logic here
909
- return await discoverNFTs(this.address, this.config)
1011
+ return await discoverEvmNFTs(this.address, this.config);
910
1012
  }
911
1013
 
912
1014
  async transferNative(to: string, amount: number): Promise<TransactionResult> {
@@ -922,25 +1024,11 @@ export class EVMChainWallet extends ChainWallet<string, string, PublicClient> {
922
1024
  async getTransactionHistory(): Promise<EVMTransactionHistoryItem[]> {
923
1025
  const wallet = this.getWallet();
924
1026
  let res: EVMTransactionHistoryItem
925
- try {
926
- return await getEVMTransactionHistory(this.connection!, this.address as Hex);
927
- } catch (error) {
928
- return []
929
- }
1027
+ return await getEvmTransactionHistorySafe(this.connection!, this.address);
930
1028
  }
931
1029
 
932
1030
  async getPrices(tokenAddresses: string[]): Promise<PriceResponse> {
933
- const result = await fetchPrices({
934
- vm: 'EVM',
935
- chainId: this.config.chainId,
936
- tokenAddresses,
937
- });
938
-
939
- if (result.error) {
940
- throw new Error(result.error.message);
941
- }
942
-
943
- return result.data as PriceResponse;
1031
+ return await getEvmPrices(this.config, tokenAddresses);
944
1032
  }
945
1033
 
946
1034
  // Updated swap method signature to match base class so created another method to use it inside swap
@@ -1006,260 +1094,4 @@ export class EVMChainWallet extends ChainWallet<string, string, PublicClient> {
1006
1094
  return signer.signMessage({ message, account: signer.account?.address })
1007
1095
  }
1008
1096
 
1009
- // // ============================================
1010
- // // Savings Pocket Methods
1011
- // // ============================================
1012
-
1013
- // /**
1014
- // * Get or create the SavingsManager instance (lazy initialization)
1015
- // * @private
1016
- // */
1017
- // private getSavingsManager(): SavingsManager {
1018
- // if (!this.savingsManager) {
1019
- // // Create a VM instance from the current wallet's seed
1020
- // // We need to get the seed from the privateKey
1021
- // // For now, we'll create an EVMVM from the wallet
1022
- // // Note: This requires access to the seed, which we'll need to handle
1023
- // throw new Error(
1024
- // "SavingsManager requires access to the seed phrase. " +
1025
- // "Please initialize the wallet with a seed phrase or mnemonic to use savings features."
1026
- // );
1027
- // }
1028
- // return this.savingsManager;
1029
- // }
1030
-
1031
- // /**
1032
- // * Initialize savings functionality with a seed phrase
1033
- // *
1034
- // * This must be called before using any savings methods.
1035
- // * The seed is used to derive savings accounts using BIP-44.
1036
- // *
1037
- // * @param seed - The wallet seed (hex string)
1038
- // *
1039
- // * @example
1040
- // * const seed = VM.mnemonicToSeed(mnemonic);
1041
- // * wallet.initializeSavings(seed);
1042
- // */
1043
- // initializeSavings(seed: string): void {
1044
- // const vm = new EVMVM(seed);
1045
- // this.savingsManager = new SavingsManager(vm);
1046
- // }
1047
-
1048
- // /**
1049
- // * Derive a new savings account from BIP-44 account index
1050
- // *
1051
- // * @param accountIndex - The BIP-44 account index (1+ for savings, 0 is main wallet)
1052
- // * @returns SavingsAccount with derived address and private key
1053
- // *
1054
- // * @example
1055
- // * const savingsAccount1 = wallet.deriveSavingsAccount(1); // m/44'/60'/1'/0/0
1056
- // * const savingsAccount2 = wallet.deriveSavingsAccount(2); // m/44'/60'/2'/0/0
1057
- // */
1058
- // deriveSavingsAccount(accountIndex: number): SavingsAccount {
1059
- // return this.getSavingsManager().createSavingsAccount(accountIndex);
1060
- // }
1061
-
1062
- // /**
1063
- // * Transfer native tokens to a savings account
1064
- // *
1065
- // * Security: Always derives the destination address from accountIndex.
1066
- // *
1067
- // * @param accountIndex - Savings account index to deposit to
1068
- // * @param amount - Amount in ether units (e.g., "1.5" for 1.5 ETH)
1069
- // * @param options - Optional security and priority settings
1070
- // * @returns Transaction result
1071
- // *
1072
- // * @example
1073
- // * const result = await wallet.transferToSavings(1, "1.5"); // Send 1.5 ETH to savings account 1
1074
- // */
1075
- // async transferToSavings(
1076
- // accountIndex: number,
1077
- // amount: string,
1078
- // options?: TransferToSavingsOptions
1079
- // ): Promise<TransactionResult> {
1080
- // const manager = this.getSavingsManager();
1081
-
1082
- // // Build transaction using derived address
1083
- // const amountWei = parseEther(amount);
1084
- // const txParams = manager.buildDepositTransaction(accountIndex, amountWei, options);
1085
-
1086
- // // Execute using existing transferNative method
1087
- // return await this.transferNative(txParams.to, Number(amount));
1088
- // }
1089
-
1090
- // // /**
1091
- // // * Withdraw native tokens from a savings account
1092
- // // *
1093
- // // * Security: Uses the derived private key for signing.
1094
- // // *
1095
- // // * @param accountIndex - Savings account index to withdraw from
1096
- // // * @param to - Destination address
1097
- // // * @param amount - Amount in ether units (e.g., "0.5" for 0.5 ETH)
1098
- // // * @param options - Optional security and priority settings
1099
- // // * @returns Transaction result
1100
- // // *
1101
- // // * @example
1102
- // // * const result = await wallet.withdrawFromSavings(1, destinationAddress, "0.5");
1103
- // // */
1104
- // // async withdrawFromSavings(
1105
- // // accountIndex: number,
1106
- // // to: string,
1107
- // // amount: string,
1108
- // // options?: WithdrawFromSavingsOptions
1109
- // // ): Promise<TransactionResult> {
1110
- // // const manager = this.getSavingsManager();
1111
-
1112
- // // // Build withdrawal transaction
1113
- // // const amountWei = parseEther(amount);
1114
- // // const withdrawalParams = manager.buildWithdrawalTransaction(
1115
- // // accountIndex,
1116
- // // to as Hex,
1117
- // // amountWei,
1118
- // // options
1119
- // // );
1120
-
1121
- // // // Create a temporary wallet with the savings account private key
1122
- // // const savingsWallet = new Wallet(withdrawalParams.privateKey, this.connection);
1123
-
1124
- // // // Send transaction using the savings wallet
1125
- // // const tx = await savingsWallet.sendTransaction({
1126
- // // to: withdrawalParams.to,
1127
- // // value: withdrawalParams.value
1128
- // // });
1129
-
1130
- // // const receipt = await tx.wait(this.config.confirmationNo || 1);
1131
-
1132
- // // return {
1133
- // // success: receipt?.status === 1,
1134
- // // hash: receipt?.hash || tx.hash
1135
- // // };
1136
- // // }
1137
-
1138
- // /**
1139
- // * Verify a stored savings address matches the derived address
1140
- // *
1141
- // * Security: Prevents database tampering attacks.
1142
- // *
1143
- // * @param accountIndex - The account index to verify
1144
- // * @param storedAddress - The address from storage/database
1145
- // * @returns Verification result
1146
- // *
1147
- // * @example
1148
- // * const result = wallet.verifySavingsAddress(1, storedAddress);
1149
- // * if (!result.isValid) {
1150
- // * console.error("Security alert: Address tampering detected!");
1151
- // * }
1152
- // */
1153
- // verifySavingsAddress(accountIndex: number, storedAddress: Hex): AddressVerificationResult {
1154
- // return this.getSavingsManager().verifySavingsAddress(accountIndex, storedAddress);
1155
- // }
1156
-
1157
- // /**
1158
- // * Audit multiple savings addresses at once
1159
- // *
1160
- // * @param addresses - Map of accountIndex to stored address
1161
- // * @returns Audit result with summary and details
1162
- // *
1163
- // * @example
1164
- // * const addresses = new Map([[1, "0xabc..."], [2, "0xdef..."]]);
1165
- // * const audit = wallet.auditSavingsAddresses(addresses);
1166
- // * console.log(`Valid: ${audit.valid}/${audit.total}`);
1167
- // */
1168
- // auditSavingsAddresses(addresses: Map<number, Hex>): SavingsAuditResult {
1169
- // return this.getSavingsManager().auditSavingsAddresses(addresses);
1170
- // }
1171
-
1172
- // /**
1173
- // * Get savings account information without exposing private key
1174
- // *
1175
- // * @param accountIndex - The account index
1176
- // * @returns Public account information (address and derivation path)
1177
- // *
1178
- // * @example
1179
- // * const info = wallet.getSavingsAccountInfo(1);
1180
- // * console.log(`Address: ${info.address}`);
1181
- // * console.log(`Path: ${info.derivationPath}`); // m/44'/60'/1'/0/0
1182
- // */
1183
- // getSavingsAccountInfo(accountIndex: number): Omit<SavingsAccount, 'privateKey'> {
1184
- // return this.getSavingsManager().getSavingsAccountInfo(accountIndex);
1185
- // }
1186
-
1187
- // // ============================================
1188
- // // Smart Savings Methods (EIP-7702)
1189
- // // ============================================
1190
-
1191
- // /**
1192
- // * Get or create the SmartSavingsManager instance (lazy initialization)
1193
- // * @private
1194
- // */
1195
- // private getSmartSavingsManager(): SmartSavingsManager {
1196
- // if (!this.smartSavingsManager) {
1197
- // this.smartSavingsManager = new SmartSavingsManager(this.config);
1198
- // }
1199
- // return this.smartSavingsManager;
1200
- // }
1201
-
1202
- // /**
1203
- // * Upgrade a savings account to a smart account with EIP-7702 delegation
1204
- // *
1205
- // * This enables advanced features:
1206
- // * - Lock modules for time-locked savings
1207
- // * - Hooks for spend & save
1208
- // * - Session keys for periodic savings
1209
- // * - Sponsored transactions via paymaster
1210
- // *
1211
- // * @param accountIndex - The savings account index to upgrade
1212
- // * @param options - Optional smart wallet configuration
1213
- // * @param autoInitialize - Whether to initialize the smart wallet (default: false)
1214
- // * @returns SmartSavingsAccount with EVMSmartWallet instance
1215
- // *
1216
- // * @example
1217
- // * // Upgrade without initialization
1218
- // * const smartSavings = await wallet.upgradeSavingsToSmartAccount(1);
1219
- // * await smartSavings.smartWallet.initialize(); // Initialize separately
1220
- // *
1221
- // * @example
1222
- // * // Upgrade and initialize in one step
1223
- // * const smartSavings = await wallet.upgradeSavingsToSmartAccount(1, {}, true);
1224
- // * // Ready to use immediately
1225
- // */
1226
- // async upgradeSavingsToSmartAccount(
1227
- // accountIndex: number,
1228
- // options?: SmartWalletOptions,
1229
- // autoInitialize: boolean = false
1230
- // ): Promise<SmartSavingsAccount> {
1231
- // const manager = this.getSmartSavingsManager();
1232
-
1233
- // // First derive the basic savings account
1234
- // const basicSavings = this.deriveSavingsAccount(accountIndex);
1235
-
1236
- // // Then upgrade to smart account
1237
- // if (autoInitialize) {
1238
- // return await manager.upgradeSavingsAndInitialize(basicSavings, options);
1239
- // } else {
1240
- // return await manager.upgradeSavingsToSmartAccount(basicSavings, options);
1241
- // }
1242
- // }
1243
-
1244
- // /**
1245
- // * Check if smart savings is supported on this chain
1246
- // *
1247
- // * @returns true if chain supports Account Abstraction
1248
- // *
1249
- // * @example
1250
- // * if (wallet.isSmartSavingsSupported()) {
1251
- // * const smartSavings = await wallet.upgradeSavingsToSmartAccount(1);
1252
- // * } else {
1253
- // * console.log("This chain doesn't support smart savings");
1254
- // * }
1255
- // */
1256
- // isSmartSavingsSupported(): boolean {
1257
- // try {
1258
- // const manager = this.getSmartSavingsManager();
1259
- // return manager.canUpgradeToSmartAccount();
1260
- // } catch (error) {
1261
- // return false;
1262
- // }
1263
- // }
1264
1097
  }
1265
-
@@ -13,6 +13,8 @@ import {
13
13
  encodeFunctionData,
14
14
  parseEther,
15
15
  formatEther,
16
+ createPublicClient,
17
+ http,
16
18
  } from 'viem'
17
19
  export interface TransactionParams {
18
20
  to: string
@@ -236,6 +238,16 @@ export const fromChainToViemChain = (config: ChainWalletConfig): Chain => {
236
238
 
237
239
 
238
240
  }
241
+
242
+
243
+ export const createPublicClientFromChainConfig = (chain: ChainWalletConfig): PublicClient => {
244
+ return createPublicClient({
245
+ chain: fromChainToViemChain(chain),
246
+ transport: http(chain.rpcUrl)
247
+ });
248
+ }
249
+
250
+
239
251
  export function viemReceiptToEthersReceipt(
240
252
  receipt: ViemTransactionReceipt,
241
253
  ): EthersTransactionReceipt {
package/utils/index.ts CHANGED
@@ -6,7 +6,7 @@ export * from "./vm"
6
6
  // Note: Utility functions (discoverTokens, getTokenBalance, etc.) have name conflicts
7
7
  // Import them directly from './evm' or './svm' submodules when needed
8
8
  export { EVMVM, EVMChainWallet, EVMSmartWallet } from "./evm"
9
- export { SVMVM, SVMChainWallet, } from "./svm"
9
+ export { SVMVM, SVMChainWallet, SVMChainAddress } from "./svm"
10
10
 
11
11
  // Re-export all EVM exports as namespace to avoid conflicts
12
12
  export * as evm from "./evm"
@@ -17,4 +17,4 @@ export * from "./constant"
17
17
  export * from "bs58"
18
18
  export * from "@solana/web3.js"
19
19
  export * from "./price"
20
- export * from "./utils"
20
+ export * from "./utils"
@@ -43,7 +43,7 @@ import BN from "bn.js";
43
43
  */
44
44
  export class SVMSavingsManager extends SavingsManager<PublicKey, Connection, Keypair> {
45
45
  coinType = 501;
46
- derivationPathBase = "m/44'/501'/";
46
+ derivationPathBase = "m/44'/501'/"; // Base path for account derivation
47
47
 
48
48
  private rpcUrl: string;
49
49
  private _client?: Connection;