@deserialize/multi-vm-wallet 1.5.21 → 1.5.31
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/dist/IChainWallet.d.ts +11 -7
- package/dist/IChainWallet.js +15 -6
- package/dist/constant.js +40 -48
- package/dist/evm/evm.d.ts +19 -1
- package/dist/evm/evm.js +90 -32
- package/dist/evm/utils.d.ts +1 -0
- package/dist/evm/utils.js +8 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -1
- package/dist/svm/svm.d.ts +17 -1
- package/dist/svm/svm.js +71 -21
- package/dist/test.js +12 -0
- package/dist/types.d.ts +4 -0
- package/package.json +1 -1
- package/utils/IChainWallet.ts +76 -15
- package/utils/constant.ts +41 -51
- package/utils/evm/evm.ts +371 -291
- package/utils/evm/utils.ts +12 -0
- package/utils/index.ts +2 -2
- package/utils/savings/svm-savings.ts +1 -1
- package/utils/svm/svm.ts +344 -24
- package/utils/test.ts +18 -3
- package/utils/types.ts +6 -2
- package/utils/utils.ts +7 -0
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,133 @@ import { Account, generatePrivateKey, privateKeyToAccount } from "viem/accounts"
|
|
|
50
50
|
// import { extendWalletClientWithSavings } from "../savings";
|
|
51
51
|
// import { SavingsManager } from "../savings/saving-actions";
|
|
52
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Create a viem public client for the given EVM chain configuration.
|
|
55
|
+
*
|
|
56
|
+
* @param config - Chain configuration with RPC endpoint and chain metadata.
|
|
57
|
+
* @returns Configured viem `PublicClient`.
|
|
58
|
+
*/
|
|
59
|
+
export const createEvmPublicClient = (config: ChainWalletConfig): PublicClient =>
|
|
60
|
+
createPublicClient({
|
|
61
|
+
chain: fromChainToViemChain(config),
|
|
62
|
+
transport: http(config.rpcUrl),
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Create a viem wallet client bound to a specific account.
|
|
67
|
+
*
|
|
68
|
+
* @param config - Chain configuration with RPC endpoint and chain metadata.
|
|
69
|
+
* @param account - Account used for signing transactions and messages.
|
|
70
|
+
* @returns Configured viem `WalletClient`.
|
|
71
|
+
*/
|
|
72
|
+
export const createEvmWalletClient = (config: ChainWalletConfig, account: Account): WalletClient =>
|
|
73
|
+
createWalletClient({
|
|
74
|
+
account,
|
|
75
|
+
chain: fromChainToViemChain(config),
|
|
76
|
+
transport: http(config.rpcUrl),
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Fetch transaction history and return an empty array on failure.
|
|
81
|
+
*
|
|
82
|
+
* @param connection - viem public client used to query chain data.
|
|
83
|
+
* @param address - Wallet address to inspect.
|
|
84
|
+
* @returns Parsed EVM transaction history items.
|
|
85
|
+
*/
|
|
86
|
+
export const getEvmTransactionHistorySafe = async (
|
|
87
|
+
connection: PublicClient,
|
|
88
|
+
address: string
|
|
89
|
+
): Promise<EVMTransactionHistoryItem[]> => {
|
|
90
|
+
try {
|
|
91
|
+
return await getEVMTransactionHistory(connection, address as Hex);
|
|
92
|
+
} catch {
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Fetch token prices for EVM tokens on the configured chain.
|
|
99
|
+
*
|
|
100
|
+
* @param config - Chain configuration used for chain ID resolution.
|
|
101
|
+
* @param tokenAddresses - Token contract addresses to query.
|
|
102
|
+
* @returns Price data keyed by token address.
|
|
103
|
+
* @throws Error when the pricing service returns an error payload.
|
|
104
|
+
*/
|
|
105
|
+
export const getSvmPricesForTokens = async (
|
|
106
|
+
config: ChainWalletConfig,
|
|
107
|
+
tokenAddresses: string[]
|
|
108
|
+
): Promise<PriceResponse> => {
|
|
109
|
+
const result = await fetchPrices({
|
|
110
|
+
vm: 'EVM',
|
|
111
|
+
chainId: config.chainId,
|
|
112
|
+
tokenAddresses,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
if (result.error) {
|
|
116
|
+
throw new Error(result.error.message);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return result.data as PriceResponse;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Get native token balance for an address.
|
|
124
|
+
*
|
|
125
|
+
* @param address - Wallet address to query.
|
|
126
|
+
* @param connection - viem public client.
|
|
127
|
+
* @returns Native balance details.
|
|
128
|
+
*/
|
|
129
|
+
export const getEvmNativeBalance = async (
|
|
130
|
+
address: string,
|
|
131
|
+
connection: PublicClient
|
|
132
|
+
): Promise<Balance> => {
|
|
133
|
+
return await EVMVM.getNativeBalance(address, connection);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Get ERC-20 token balance for an address.
|
|
138
|
+
*
|
|
139
|
+
* @param address - Wallet address to query.
|
|
140
|
+
* @param tokenAddress - ERC-20 contract address.
|
|
141
|
+
* @param connection - viem public client.
|
|
142
|
+
* @returns Token balance details.
|
|
143
|
+
*/
|
|
144
|
+
export const getEvmTokenBalance = async (
|
|
145
|
+
address: string,
|
|
146
|
+
tokenAddress: string,
|
|
147
|
+
connection: PublicClient
|
|
148
|
+
): Promise<Balance> => {
|
|
149
|
+
return await EVMVM.getTokenBalance(address, tokenAddress, connection);
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Discover token balances held by an address.
|
|
154
|
+
*
|
|
155
|
+
* @param address - Wallet address to scan.
|
|
156
|
+
* @param config - Chain configuration.
|
|
157
|
+
* @returns Discovered token balances.
|
|
158
|
+
*/
|
|
159
|
+
export const discoverEvmTokens = async (
|
|
160
|
+
address: string,
|
|
161
|
+
config: ChainWalletConfig
|
|
162
|
+
): Promise<UserTokenBalance<string>[]> => {
|
|
163
|
+
return await discoverTokens(address, config);
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Discover NFTs held by an address.
|
|
168
|
+
*
|
|
169
|
+
* @param address - Wallet address to scan.
|
|
170
|
+
* @param config - Chain configuration.
|
|
171
|
+
* @returns Discovered NFT items.
|
|
172
|
+
*/
|
|
173
|
+
export const discoverEvmNFTs = async (
|
|
174
|
+
address: string,
|
|
175
|
+
config: ChainWalletConfig
|
|
176
|
+
): Promise<NFT[]> => {
|
|
177
|
+
return await discoverNFTs(address, config);
|
|
178
|
+
};
|
|
179
|
+
|
|
53
180
|
|
|
54
181
|
interface DebonkQuoteResponse {
|
|
55
182
|
tokenA: string;
|
|
@@ -98,6 +225,15 @@ export class EVMVM extends VM<string, string, PublicClient> {
|
|
|
98
225
|
|
|
99
226
|
getTokenInfo = getTokenInfo
|
|
100
227
|
static getTokenInfo = getTokenInfo
|
|
228
|
+
/**
|
|
229
|
+
* Derive an EVM private key for a wallet index.
|
|
230
|
+
*
|
|
231
|
+
* @param index - Wallet index in the derivation path.
|
|
232
|
+
* @param seed - Optional explicit seed (takes priority over mnemonic).
|
|
233
|
+
* @param mnemonic - Optional mnemonic used when seed is not provided.
|
|
234
|
+
* @param derivationPath - Base derivation path prefix.
|
|
235
|
+
* @returns Derived private key and index.
|
|
236
|
+
*/
|
|
101
237
|
generatePrivateKey(index: number, seed?: string, mnemonic?: string, derivationPath = this.derivationPath) {
|
|
102
238
|
// Validate inputs
|
|
103
239
|
VMValidation.validateIndex(index, 'Wallet index');
|
|
@@ -121,10 +257,22 @@ export class EVMVM extends VM<string, string, PublicClient> {
|
|
|
121
257
|
return { privateKey, index };
|
|
122
258
|
}
|
|
123
259
|
|
|
260
|
+
/**
|
|
261
|
+
* Convert raw private key entropy into a mnemonic phrase.
|
|
262
|
+
*
|
|
263
|
+
* @param privateKey - Private key entropy input.
|
|
264
|
+
* @returns Generated mnemonic phrase.
|
|
265
|
+
*/
|
|
124
266
|
static generateMnemonicFromPrivateKey(privateKey: string): string {
|
|
125
267
|
|
|
126
268
|
return EntropyToMnemonic(privateKey)
|
|
127
269
|
}
|
|
270
|
+
/**
|
|
271
|
+
* Create an `EVMVM` instance from a mnemonic phrase.
|
|
272
|
+
*
|
|
273
|
+
* @param mnemonic - BIP-39 mnemonic phrase.
|
|
274
|
+
* @returns Initialized EVM VM instance.
|
|
275
|
+
*/
|
|
128
276
|
static fromMnemonic(mnemonic: string): VM<string, string, PublicClient> {
|
|
129
277
|
const seed = VM.mnemonicToSeed(mnemonic)
|
|
130
278
|
return new EVMVM(seed)
|
|
@@ -191,18 +339,40 @@ export class EVMVM extends VM<string, string, PublicClient> {
|
|
|
191
339
|
return ethers.getAddress(address);
|
|
192
340
|
}
|
|
193
341
|
|
|
342
|
+
/**
|
|
343
|
+
* Read the native token balance for an address.
|
|
344
|
+
*
|
|
345
|
+
* @param address - Wallet address to query.
|
|
346
|
+
* @param connection - viem public client.
|
|
347
|
+
* @returns Native balance details.
|
|
348
|
+
*/
|
|
194
349
|
static async getNativeBalance(address: string, connection: PublicClient): Promise<Balance> {
|
|
195
350
|
// Implement native balance retrieval logic here
|
|
196
351
|
return await getNativeBalance(address as Hex, connection)
|
|
197
352
|
}
|
|
198
353
|
|
|
354
|
+
/**
|
|
355
|
+
* Read an ERC-20 token balance for an address.
|
|
356
|
+
*
|
|
357
|
+
* @param address - Wallet address that owns the token.
|
|
358
|
+
* @param tokenAddress - ERC-20 contract address.
|
|
359
|
+
* @param connection - viem public client.
|
|
360
|
+
* @returns Token balance details.
|
|
361
|
+
*/
|
|
199
362
|
static async getTokenBalance(address: string, tokenAddress: string, connection: PublicClient): Promise<Balance> {
|
|
200
363
|
// Implement token balance retrieval logic here
|
|
201
364
|
return await getTokenBalance(tokenAddress as Hex, address as Hex, connection)
|
|
202
365
|
}
|
|
203
366
|
|
|
367
|
+
/**
|
|
368
|
+
* Convert arbitrary entropy text into a deterministic private-key-like hash.
|
|
369
|
+
*
|
|
370
|
+
* @param entropy - Input entropy string.
|
|
371
|
+
* @returns `keccak256` hash of the input.
|
|
372
|
+
*/
|
|
204
373
|
static convertFromEntropyToPrivateKey = (entropy: string): string => {
|
|
205
|
-
|
|
374
|
+
const p = ethers.id(entropy)
|
|
375
|
+
return p
|
|
206
376
|
}
|
|
207
377
|
|
|
208
378
|
/**
|
|
@@ -687,29 +857,106 @@ export class EVMVM extends VM<string, string, PublicClient> {
|
|
|
687
857
|
|
|
688
858
|
}
|
|
689
859
|
|
|
860
|
+
export class EVMChainAddress extends ChainAddress<string, PublicClient> {
|
|
861
|
+
/**
|
|
862
|
+
* Create an EVM chain address wrapper with an attached public client.
|
|
863
|
+
*
|
|
864
|
+
* @param config - Chain configuration.
|
|
865
|
+
* @param address - Wallet address.
|
|
866
|
+
* @param index - Optional derivation index.
|
|
867
|
+
*/
|
|
868
|
+
constructor(config: ChainWalletConfig, address: string, index?: number) {
|
|
869
|
+
const connection = createEvmPublicClient(config);
|
|
870
|
+
super(config, address, index);
|
|
871
|
+
this.connection = connection;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
/**
|
|
875
|
+
* Get native balance for this address.
|
|
876
|
+
*
|
|
877
|
+
* @returns Native balance details.
|
|
878
|
+
*/
|
|
879
|
+
async getNativeBalance(): Promise<Balance> {
|
|
880
|
+
return await getEvmNativeBalance(this.address, this.connection!);
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
/**
|
|
884
|
+
* Get ERC-20 token balance for this address.
|
|
885
|
+
*
|
|
886
|
+
* @param tokenAddress - ERC-20 contract address.
|
|
887
|
+
* @returns Token balance details.
|
|
888
|
+
*/
|
|
889
|
+
async getTokenBalance(tokenAddress: string): Promise<Balance> {
|
|
890
|
+
return await getEvmTokenBalance(this.address, tokenAddress, this.connection!);
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
/**
|
|
894
|
+
* Discover fungible tokens held by this address.
|
|
895
|
+
*
|
|
896
|
+
* @returns Discovered token balances.
|
|
897
|
+
*/
|
|
898
|
+
async discoverToken(): Promise<UserTokenBalance<string>[]> {
|
|
899
|
+
return await discoverEvmTokens(this.address, this.config);
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
/**
|
|
903
|
+
* Discover NFTs held by this address.
|
|
904
|
+
*
|
|
905
|
+
* @returns Discovered NFTs.
|
|
906
|
+
*/
|
|
907
|
+
async discoverNFT(): Promise<NFT[]> {
|
|
908
|
+
return await discoverEvmNFTs(this.address, this.config);
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
/**
|
|
912
|
+
* Retrieve transaction history for this address.
|
|
913
|
+
*
|
|
914
|
+
* @returns Parsed transaction history entries.
|
|
915
|
+
*/
|
|
916
|
+
async getTransactionHistory(): Promise<EVMTransactionHistoryItem[]> {
|
|
917
|
+
return await getEvmTransactionHistorySafe(this.connection!, this.address);
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
/**
|
|
921
|
+
* Fetch price data for the provided token addresses.
|
|
922
|
+
*
|
|
923
|
+
* @param tokenAddresses - Token contract addresses.
|
|
924
|
+
* @returns Price response.
|
|
925
|
+
*/
|
|
926
|
+
async getPrices(tokenAddresses: string[]): Promise<PriceResponse> {
|
|
927
|
+
return await getSvmPricesForTokens(this.config, tokenAddresses);
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
|
|
690
934
|
export class EVMChainWallet extends ChainWallet<string, string, PublicClient> {
|
|
691
935
|
wallet: WalletClient
|
|
692
936
|
private smartWallet?: EVMSmartWallet
|
|
693
937
|
// private savingsManager?: SavingsManager
|
|
694
938
|
// private smartSavingsManager?: SmartSavingsManager
|
|
695
939
|
|
|
940
|
+
/**
|
|
941
|
+
* Create an EVM wallet bound to a chain configuration and private key.
|
|
942
|
+
*
|
|
943
|
+
* @param config - Chain configuration.
|
|
944
|
+
* @param privateKey - Hex private key (with or without `0x` prefix).
|
|
945
|
+
* @param index - Wallet index.
|
|
946
|
+
*/
|
|
696
947
|
constructor(config: ChainWalletConfig, privateKey: string, index: number) {
|
|
697
948
|
privateKey = privateKey.startsWith('0x') ? privateKey : `0x${privateKey}`
|
|
698
|
-
|
|
699
|
-
this.connection = createPublicClient(
|
|
700
|
-
{
|
|
701
|
-
chain: fromChainToViemChain(config),
|
|
702
|
-
transport: http(config.rpcUrl)
|
|
703
|
-
},
|
|
704
|
-
)
|
|
949
|
+
const connection = createEvmPublicClient(config);
|
|
705
950
|
const account = privateKeyToAccount(privateKey as Hex)
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
this.address = account.address
|
|
951
|
+
const wallet = createEvmWalletClient(config, account);
|
|
952
|
+
const address = account.address
|
|
953
|
+
super(config, address, privateKey, index);
|
|
954
|
+
|
|
955
|
+
|
|
712
956
|
this.privateKey = privateKey;
|
|
957
|
+
this.wallet = wallet;
|
|
958
|
+
this.connection = connection;
|
|
959
|
+
this.address = address
|
|
713
960
|
}
|
|
714
961
|
|
|
715
962
|
// ============================================
|
|
@@ -724,6 +971,12 @@ export class EVMChainWallet extends ChainWallet<string, string, PublicClient> {
|
|
|
724
971
|
return this.config.aaSupport?.enabled === true;
|
|
725
972
|
}
|
|
726
973
|
|
|
974
|
+
/**
|
|
975
|
+
* Convert entropy text into a hex string.
|
|
976
|
+
*
|
|
977
|
+
* @param entropy - Entropy string.
|
|
978
|
+
* @returns Hex-encoded string.
|
|
979
|
+
*/
|
|
727
980
|
convertFromEntropyToPrivateKey = (entropy: string): string => {
|
|
728
981
|
return toHex(entropy)
|
|
729
982
|
}
|
|
@@ -877,73 +1130,132 @@ export class EVMChainWallet extends ChainWallet<string, string, PublicClient> {
|
|
|
877
1130
|
// Existing Wallet Methods
|
|
878
1131
|
// ============================================
|
|
879
1132
|
|
|
1133
|
+
/**
|
|
1134
|
+
* Get the underlying viem wallet client.
|
|
1135
|
+
*
|
|
1136
|
+
* @returns Wallet client instance.
|
|
1137
|
+
*/
|
|
880
1138
|
getWallet(): WalletClient {
|
|
881
1139
|
return this.wallet
|
|
882
1140
|
}
|
|
883
1141
|
|
|
1142
|
+
/**
|
|
1143
|
+
* Get this wallet's address.
|
|
1144
|
+
*
|
|
1145
|
+
* @returns Wallet address.
|
|
1146
|
+
*/
|
|
884
1147
|
generateAddress(): string {
|
|
885
1148
|
return this.address;
|
|
886
1149
|
}
|
|
887
1150
|
|
|
1151
|
+
/**
|
|
1152
|
+
* Get native token balance for this wallet.
|
|
1153
|
+
*
|
|
1154
|
+
* @returns Native balance details.
|
|
1155
|
+
*/
|
|
888
1156
|
async getNativeBalance(): Promise<Balance> {
|
|
889
1157
|
// Implement native balance retrieval logic here
|
|
890
|
-
return await
|
|
1158
|
+
return await getEvmNativeBalance(this.address, this.connection!);
|
|
891
1159
|
}
|
|
892
1160
|
|
|
1161
|
+
/**
|
|
1162
|
+
* Get ERC-20 token balance for this wallet.
|
|
1163
|
+
*
|
|
1164
|
+
* @param tokenAddress - ERC-20 contract address.
|
|
1165
|
+
* @returns Token balance details.
|
|
1166
|
+
*/
|
|
893
1167
|
async getTokenBalance(tokenAddress: string): Promise<Balance> {
|
|
894
1168
|
// Implement token balance retrieval logic here
|
|
895
|
-
return await
|
|
1169
|
+
return await getEvmTokenBalance(this.address, tokenAddress, this.connection!);
|
|
896
1170
|
}
|
|
897
1171
|
|
|
1172
|
+
/**
|
|
1173
|
+
* Get ERC-20 token metadata.
|
|
1174
|
+
*
|
|
1175
|
+
* @param tokenAddress - ERC-20 contract address.
|
|
1176
|
+
* @returns Token metadata returned by `getTokenInfo`.
|
|
1177
|
+
*/
|
|
898
1178
|
async getTokenInfo(tokenAddress: string) {
|
|
899
1179
|
return await EVMVM.getTokenInfo(tokenAddress as Hex, this.connection!)
|
|
900
1180
|
}
|
|
901
1181
|
|
|
1182
|
+
/**
|
|
1183
|
+
* Discover fungible tokens held by this wallet.
|
|
1184
|
+
*
|
|
1185
|
+
* @returns Discovered token balances.
|
|
1186
|
+
*/
|
|
902
1187
|
async discoverToken(): Promise<UserTokenBalance<string>[]> {
|
|
903
1188
|
// Implement token discovery logic here
|
|
904
|
-
return await
|
|
1189
|
+
return await discoverEvmTokens(this.address, this.config);
|
|
905
1190
|
}
|
|
906
1191
|
|
|
1192
|
+
/**
|
|
1193
|
+
* Discover NFTs held by this wallet.
|
|
1194
|
+
*
|
|
1195
|
+
* @returns Discovered NFTs.
|
|
1196
|
+
*/
|
|
907
1197
|
async discoverNFT(): Promise<NFT[]> {
|
|
908
1198
|
// Implement NFT discovery logic here
|
|
909
|
-
return await
|
|
1199
|
+
return await discoverEvmNFTs(this.address, this.config);
|
|
910
1200
|
}
|
|
911
1201
|
|
|
1202
|
+
/**
|
|
1203
|
+
* Send native tokens to another address.
|
|
1204
|
+
*
|
|
1205
|
+
* @param to - Recipient address.
|
|
1206
|
+
* @param amount - Amount in native token units.
|
|
1207
|
+
* @returns Transaction result.
|
|
1208
|
+
*/
|
|
912
1209
|
async transferNative(to: string, amount: number): Promise<TransactionResult> {
|
|
913
1210
|
const wallet = this.getWallet();
|
|
914
1211
|
return await sendNativeToken(wallet, this.connection!, to as Hex, amount.toString(), this.config.confirmationNo || 5);
|
|
915
1212
|
}
|
|
916
1213
|
|
|
1214
|
+
/**
|
|
1215
|
+
* Send ERC-20 tokens to another address.
|
|
1216
|
+
*
|
|
1217
|
+
* @param tokenAddress - Token info containing contract address.
|
|
1218
|
+
* @param to - Recipient address.
|
|
1219
|
+
* @param amount - Token amount to transfer.
|
|
1220
|
+
* @returns Transaction result.
|
|
1221
|
+
*/
|
|
917
1222
|
async transferToken(tokenAddress: TokenInfo, to: string, amount: number): Promise<TransactionResult> {
|
|
918
1223
|
const wallet = this.getWallet();
|
|
919
1224
|
return await sendERC20Token(wallet, this.connection!, tokenAddress.address as Hex, to as Hex, BigInt(amount.toString()), this.config.confirmationNo || 5);
|
|
920
1225
|
}
|
|
921
1226
|
|
|
1227
|
+
/**
|
|
1228
|
+
* Get transaction history for this wallet address.
|
|
1229
|
+
*
|
|
1230
|
+
* @returns Parsed transaction history entries.
|
|
1231
|
+
*/
|
|
922
1232
|
async getTransactionHistory(): Promise<EVMTransactionHistoryItem[]> {
|
|
923
1233
|
const wallet = this.getWallet();
|
|
924
1234
|
let res: EVMTransactionHistoryItem
|
|
925
|
-
|
|
926
|
-
return await getEVMTransactionHistory(this.connection!, this.address as Hex);
|
|
927
|
-
} catch (error) {
|
|
928
|
-
return []
|
|
929
|
-
}
|
|
1235
|
+
return await getEvmTransactionHistorySafe(this.connection!, this.address);
|
|
930
1236
|
}
|
|
931
1237
|
|
|
1238
|
+
/**
|
|
1239
|
+
* Fetch prices for token contracts on this wallet's chain.
|
|
1240
|
+
*
|
|
1241
|
+
* @param tokenAddresses - Token contract addresses.
|
|
1242
|
+
* @returns Price response.
|
|
1243
|
+
*/
|
|
932
1244
|
async getPrices(tokenAddresses: string[]): Promise<PriceResponse> {
|
|
933
|
-
|
|
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;
|
|
1245
|
+
return await getSvmPricesForTokens(this.config, tokenAddresses);
|
|
944
1246
|
}
|
|
945
1247
|
|
|
946
1248
|
// Updated swap method signature to match base class so created another method to use it inside swap
|
|
1249
|
+
/**
|
|
1250
|
+
* Swap tokens using the chain's swap integration.
|
|
1251
|
+
*
|
|
1252
|
+
* @param tokenAddress - Source token info.
|
|
1253
|
+
* @param to - Destination token or recipient address, depending on integration.
|
|
1254
|
+
* @param amount - Amount to swap.
|
|
1255
|
+
* @param slippage - Slippage tolerance in basis points.
|
|
1256
|
+
* @returns Transaction result.
|
|
1257
|
+
* @throws Error Always throws because this method is not implemented.
|
|
1258
|
+
*/
|
|
947
1259
|
async swap(
|
|
948
1260
|
tokenAddress: TokenInfo,
|
|
949
1261
|
to: string,
|
|
@@ -958,6 +1270,12 @@ export class EVMChainWallet extends ChainWallet<string, string, PublicClient> {
|
|
|
958
1270
|
|
|
959
1271
|
|
|
960
1272
|
// Helper method for EVMChainWallet class
|
|
1273
|
+
/**
|
|
1274
|
+
* Build a standardized failed swap result.
|
|
1275
|
+
*
|
|
1276
|
+
* @param message - Failure reason.
|
|
1277
|
+
* @returns Failed Debonk swap result.
|
|
1278
|
+
*/
|
|
961
1279
|
private fail(message: string): DebonkSwapResult {
|
|
962
1280
|
return {
|
|
963
1281
|
success: false,
|
|
@@ -970,6 +1288,17 @@ export class EVMChainWallet extends ChainWallet<string, string, PublicClient> {
|
|
|
970
1288
|
|
|
971
1289
|
|
|
972
1290
|
|
|
1291
|
+
/**
|
|
1292
|
+
* Approve ERC-20 token allowance for a spender.
|
|
1293
|
+
*
|
|
1294
|
+
* @param params - Approval parameters.
|
|
1295
|
+
* @param params.tokenAddress - ERC-20 contract address.
|
|
1296
|
+
* @param params.spender - Spender address to approve.
|
|
1297
|
+
* @param params.amountRaw - Raw allowance amount.
|
|
1298
|
+
* @param params.confirmations - Confirmation blocks to wait for.
|
|
1299
|
+
* @param params.gasLimit - Optional gas limit (currently unused in this wrapper).
|
|
1300
|
+
* @returns Transaction result.
|
|
1301
|
+
*/
|
|
973
1302
|
async approveToken(params: {
|
|
974
1303
|
tokenAddress: string
|
|
975
1304
|
spender: string
|
|
@@ -996,6 +1325,13 @@ export class EVMChainWallet extends ChainWallet<string, string, PublicClient> {
|
|
|
996
1325
|
|
|
997
1326
|
|
|
998
1327
|
|
|
1328
|
+
/**
|
|
1329
|
+
* Sign an arbitrary message with this wallet account.
|
|
1330
|
+
*
|
|
1331
|
+
* @param message - Message to sign.
|
|
1332
|
+
* @returns Hex signature string.
|
|
1333
|
+
* @throws Error if wallet account is unavailable.
|
|
1334
|
+
*/
|
|
999
1335
|
async signMessage(message: string): Promise<string> {
|
|
1000
1336
|
|
|
1001
1337
|
const signer = this.wallet
|
|
@@ -1006,260 +1342,4 @@ export class EVMChainWallet extends ChainWallet<string, string, PublicClient> {
|
|
|
1006
1342
|
return signer.signMessage({ message, account: signer.account?.address })
|
|
1007
1343
|
}
|
|
1008
1344
|
|
|
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
1345
|
}
|
|
1265
|
-
|