@deserialize/multi-vm-wallet 1.4.2 → 1.5.0
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/.claude/settings.local.json +7 -1
- package/BUILD_OPTIMIZATION_PLAN.md +640 -0
- package/BUILD_RESULTS.md +282 -0
- package/BUN_MIGRATION.md +415 -0
- package/CHANGELOG_SECURITY.md +573 -0
- package/IMPLEMENTATION_SUMMARY.md +494 -0
- package/SECURITY_AUDIT.md +1124 -0
- package/bun.lock +553 -0
- package/dist/IChainWallet.js +0 -5
- package/dist/bip32Old.js +0 -885
- package/dist/bip32Small.js +0 -79
- package/dist/bipTest.js +0 -362
- package/dist/constant.js +0 -17
- package/dist/english.js +0 -1
- package/dist/evm/aa-service/index.d.ts +0 -5
- package/dist/evm/aa-service/index.js +0 -14
- package/dist/evm/aa-service/lib/account-adapter.d.ts +0 -22
- package/dist/evm/aa-service/lib/account-adapter.js +0 -24
- package/dist/evm/aa-service/lib/kernel-account.d.ts +0 -30
- package/dist/evm/aa-service/lib/kernel-account.js +2 -67
- package/dist/evm/aa-service/lib/kernel-modules.d.ts +0 -177
- package/dist/evm/aa-service/lib/kernel-modules.js +4 -202
- package/dist/evm/aa-service/lib/session-keys.d.ts +0 -118
- package/dist/evm/aa-service/lib/session-keys.js +7 -151
- package/dist/evm/aa-service/lib/type.d.ts +0 -55
- package/dist/evm/aa-service/lib/type.js +0 -10
- package/dist/evm/aa-service/services/account-abstraction.d.ts +0 -426
- package/dist/evm/aa-service/services/account-abstraction.js +0 -461
- package/dist/evm/aa-service/services/bundler.d.ts +0 -6
- package/dist/evm/aa-service/services/bundler.js +0 -54
- package/dist/evm/evm.d.ts +9 -51
- package/dist/evm/evm.js +338 -76
- package/dist/evm/index.js +0 -3
- package/dist/evm/script.js +3 -17
- package/dist/evm/smartWallet.d.ts +0 -173
- package/dist/evm/smartWallet.js +0 -206
- package/dist/evm/smartWallet.types.d.ts +0 -6
- package/dist/evm/smartWallet.types.js +0 -8
- package/dist/evm/transaction.utils.d.ts +0 -242
- package/dist/evm/transaction.utils.js +4 -320
- package/dist/evm/transactionParsing.d.ts +0 -11
- package/dist/evm/transactionParsing.js +28 -147
- package/dist/evm/utils.d.ts +0 -46
- package/dist/evm/utils.js +1 -57
- package/dist/helpers/index.d.ts +0 -4
- package/dist/helpers/index.js +8 -44
- package/dist/helpers/routeScan.js +0 -1
- package/dist/index.js +0 -1
- package/dist/old.js +0 -884
- package/dist/price.js +0 -1
- package/dist/price.types.js +0 -2
- package/dist/rate-limiter.d.ts +28 -0
- package/dist/rate-limiter.js +95 -0
- package/dist/retry-logic.d.ts +14 -0
- package/dist/retry-logic.js +120 -0
- package/dist/savings/index.js +0 -1
- package/dist/savings/saving-manager.d.ts +10 -11
- package/dist/savings/saving-manager.js +79 -22
- package/dist/savings/savings-operations.d.ts +39 -0
- package/dist/savings/savings-operations.js +141 -0
- package/dist/savings/smart-savings.d.ts +0 -63
- package/dist/savings/smart-savings.js +0 -78
- package/dist/savings/types.d.ts +0 -69
- package/dist/savings/types.js +0 -7
- package/dist/savings/validation.d.ts +9 -0
- package/dist/savings/validation.js +85 -0
- package/dist/svm/constant.js +0 -1
- package/dist/svm/index.js +0 -1
- package/dist/svm/svm.d.ts +11 -1
- package/dist/svm/svm.js +267 -27
- package/dist/svm/transactionParsing.d.ts +0 -7
- package/dist/svm/transactionParsing.js +3 -41
- package/dist/svm/transactionSender.js +0 -9
- package/dist/svm/utils.d.ts +0 -12
- package/dist/svm/utils.js +9 -60
- package/dist/test.d.ts +0 -4
- package/dist/test.js +6 -98
- package/dist/transaction-utils.d.ts +38 -0
- package/dist/transaction-utils.js +168 -0
- package/dist/types.d.ts +36 -0
- package/dist/types.js +0 -1
- package/dist/utils.js +0 -1
- package/dist/vm-validation.d.ts +11 -0
- package/dist/vm-validation.js +151 -0
- package/dist/vm.d.ts +12 -2
- package/dist/vm.js +61 -16
- package/dist/walletBip32.js +15 -70
- package/package.json +9 -4
- package/test-discovery.ts +235 -0
- package/test-pocket-discovery.ts +84 -0
- package/tsconfig.json +18 -11
- package/tsconfig.prod.json +10 -0
- package/utils/evm/evm.ts +554 -8
- package/utils/rate-limiter.ts +179 -0
- package/utils/retry-logic.ts +271 -0
- package/utils/savings/EXAMPLES.md +883 -0
- package/utils/savings/SECURITY.md +731 -0
- package/utils/savings/saving-manager.ts +526 -16
- package/utils/savings/savings-operations.ts +509 -0
- package/utils/savings/validation.ts +187 -0
- package/utils/svm/svm.ts +476 -5
- package/utils/test.ts +2 -2
- package/utils/transaction-utils.ts +394 -0
- package/utils/types.ts +100 -0
- package/utils/vm-validation.ts +280 -0
- package/utils/vm.ts +197 -10
- package/utils/walletBip32.ts +39 -3
- package/dist/IChainWallet.js.map +0 -1
- package/dist/bip32.d.ts +0 -9
- package/dist/bip32.js +0 -172
- package/dist/bip32.js.map +0 -1
- package/dist/bip32Old.js.map +0 -1
- package/dist/bip32Small.js.map +0 -1
- package/dist/bipTest.js.map +0 -1
- package/dist/constant.js.map +0 -1
- package/dist/english.js.map +0 -1
- package/dist/evm/SMART_WALLET_EXAMPLES.d.ts +0 -20
- package/dist/evm/SMART_WALLET_EXAMPLES.js +0 -451
- package/dist/evm/SMART_WALLET_EXAMPLES.js.map +0 -1
- package/dist/evm/aa-service/index.js.map +0 -1
- package/dist/evm/aa-service/lib/account-adapter.js.map +0 -1
- package/dist/evm/aa-service/lib/kernel-account.js.map +0 -1
- package/dist/evm/aa-service/lib/kernel-modules.js.map +0 -1
- package/dist/evm/aa-service/lib/session-keys.js.map +0 -1
- package/dist/evm/aa-service/lib/type.js.map +0 -1
- package/dist/evm/aa-service/services/account-abstraction.js.map +0 -1
- package/dist/evm/aa-service/services/bundler.js.map +0 -1
- package/dist/evm/evm.js.map +0 -1
- package/dist/evm/index.js.map +0 -1
- package/dist/evm/script.js.map +0 -1
- package/dist/evm/smartWallet.js.map +0 -1
- package/dist/evm/smartWallet.types.js.map +0 -1
- package/dist/evm/transaction.utils.js.map +0 -1
- package/dist/evm/transactionParsing.js.map +0 -1
- package/dist/evm/utils.js.map +0 -1
- package/dist/helpers/index.js.map +0 -1
- package/dist/helpers/routeScan.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/old.js.map +0 -1
- package/dist/price.js.map +0 -1
- package/dist/price.types.js.map +0 -1
- package/dist/privacy/artifact-manager.d.ts +0 -117
- package/dist/privacy/artifact-manager.js +0 -251
- package/dist/privacy/artifact-manager.js.map +0 -1
- package/dist/privacy/broadcaster-client.d.ts +0 -166
- package/dist/privacy/broadcaster-client.js +0 -261
- package/dist/privacy/broadcaster-client.js.map +0 -1
- package/dist/privacy/index.d.ts +0 -34
- package/dist/privacy/index.js +0 -56
- package/dist/privacy/index.js.map +0 -1
- package/dist/privacy/network-config.d.ts +0 -57
- package/dist/privacy/network-config.js +0 -118
- package/dist/privacy/network-config.js.map +0 -1
- package/dist/privacy/poi-helper.d.ts +0 -161
- package/dist/privacy/poi-helper.js +0 -249
- package/dist/privacy/poi-helper.js.map +0 -1
- package/dist/privacy/railgun-engine.d.ts +0 -135
- package/dist/privacy/railgun-engine.js +0 -205
- package/dist/privacy/railgun-engine.js.map +0 -1
- package/dist/privacy/railgun-privacy-wallet.d.ts +0 -288
- package/dist/privacy/railgun-privacy-wallet.js +0 -539
- package/dist/privacy/railgun-privacy-wallet.js.map +0 -1
- package/dist/privacy/types.d.ts +0 -229
- package/dist/privacy/types.js +0 -26
- package/dist/privacy/types.js.map +0 -1
- package/dist/savings/index.js.map +0 -1
- package/dist/savings/saving-actions.d.ts +0 -0
- package/dist/savings/saving-actions.js +0 -78
- package/dist/savings/saving-actions.js.map +0 -1
- package/dist/savings/saving-manager.js.map +0 -1
- package/dist/savings/savings-manager.d.ts +0 -126
- package/dist/savings/savings-manager.js +0 -234
- package/dist/savings/savings-manager.js.map +0 -1
- package/dist/savings/smart-savings.js.map +0 -1
- package/dist/savings/types.js.map +0 -1
- package/dist/svm/constant.js.map +0 -1
- package/dist/svm/index.js.map +0 -1
- package/dist/svm/svm.js.map +0 -1
- package/dist/svm/transactionParsing.js.map +0 -1
- package/dist/svm/transactionSender.js.map +0 -1
- package/dist/svm/utils.js.map +0 -1
- package/dist/test.js.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/utils.js.map +0 -1
- package/dist/vm.js.map +0 -1
- package/dist/walletBip32.js.map +0 -1
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transaction utilities for EVM chains
|
|
3
|
+
*
|
|
4
|
+
* Provides helpers for transaction validation, timeout handling,
|
|
5
|
+
* nonce management, and gas estimation.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { JsonRpcProvider } from 'ethers';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Transaction amount validation options
|
|
12
|
+
*/
|
|
13
|
+
export interface AmountValidationOptions {
|
|
14
|
+
/** Maximum amount allowed */
|
|
15
|
+
maxAmount?: bigint;
|
|
16
|
+
/** Minimum amount (default: 1 to prevent dust) */
|
|
17
|
+
minAmount?: bigint;
|
|
18
|
+
/** Require positive amount (default: true) */
|
|
19
|
+
requirePositive?: boolean;
|
|
20
|
+
/** Allow transferring full balance (default: false) */
|
|
21
|
+
allowFullBalance?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Validate transfer amount
|
|
26
|
+
*
|
|
27
|
+
* @param amount - Amount to transfer
|
|
28
|
+
* @param balance - Available balance
|
|
29
|
+
* @param options - Validation options
|
|
30
|
+
* @throws Error if amount is invalid
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* const balance = await provider.getBalance(address);
|
|
35
|
+
* validateTransferAmount(parseEther('1.0'), balance, {
|
|
36
|
+
* allowFullBalance: true,
|
|
37
|
+
* minAmount: parseEther('0.001')
|
|
38
|
+
* });
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export function validateTransferAmount(
|
|
42
|
+
amount: bigint,
|
|
43
|
+
balance: bigint,
|
|
44
|
+
options?: AmountValidationOptions
|
|
45
|
+
): void {
|
|
46
|
+
const {
|
|
47
|
+
maxAmount,
|
|
48
|
+
minAmount = 1n,
|
|
49
|
+
requirePositive = true,
|
|
50
|
+
allowFullBalance = false
|
|
51
|
+
} = options || {};
|
|
52
|
+
|
|
53
|
+
// Check positive
|
|
54
|
+
if (requirePositive && amount <= 0n) {
|
|
55
|
+
throw new Error(`Amount must be positive, got: ${amount}`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Check minimum (prevent dust)
|
|
59
|
+
if (amount < minAmount) {
|
|
60
|
+
throw new Error(
|
|
61
|
+
`Amount below minimum: ${amount} < ${minAmount}`
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Check maximum
|
|
66
|
+
if (maxAmount && amount > maxAmount) {
|
|
67
|
+
throw new Error(
|
|
68
|
+
`Amount exceeds maximum: ${amount} > ${maxAmount}`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Check balance
|
|
73
|
+
if (amount > balance) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
`Insufficient balance: ${amount} > ${balance}`
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Check full balance transfer
|
|
80
|
+
if (!allowFullBalance && amount === balance) {
|
|
81
|
+
throw new Error(
|
|
82
|
+
'Transferring entire balance requires explicit confirmation. ' +
|
|
83
|
+
'Set allowFullBalance: true to proceed, or leave some balance for gas fees.'
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Wait for transaction confirmation with timeout
|
|
90
|
+
*
|
|
91
|
+
* @param txResponse - Transaction response from ethers.js
|
|
92
|
+
* @param confirmations - Number of confirmations to wait for
|
|
93
|
+
* @param timeoutMs - Timeout in milliseconds
|
|
94
|
+
* @returns Transaction receipt
|
|
95
|
+
* @throws Error if timeout or confirmation fails
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```typescript
|
|
99
|
+
* const txResponse = await wallet.sendTransaction({...});
|
|
100
|
+
* const receipt = await waitForTransaction(txResponse, 1, 60000);
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
export async function waitForTransaction(
|
|
104
|
+
txResponse: any,
|
|
105
|
+
confirmations: number = 1,
|
|
106
|
+
timeoutMs: number = 60000
|
|
107
|
+
): Promise<any> {
|
|
108
|
+
const txHash = txResponse.hash;
|
|
109
|
+
|
|
110
|
+
const timeoutPromise = new Promise((_, reject) =>
|
|
111
|
+
setTimeout(
|
|
112
|
+
() => reject(new Error(`Transaction confirmation timeout after ${timeoutMs}ms`)),
|
|
113
|
+
timeoutMs
|
|
114
|
+
)
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
const confirmationPromise = txResponse.wait(confirmations);
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
const receipt = await Promise.race([
|
|
121
|
+
confirmationPromise,
|
|
122
|
+
timeoutPromise
|
|
123
|
+
]);
|
|
124
|
+
|
|
125
|
+
return receipt;
|
|
126
|
+
} catch (error: any) {
|
|
127
|
+
if (error.message.includes('timeout')) {
|
|
128
|
+
// Transaction may still be pending
|
|
129
|
+
throw new Error(
|
|
130
|
+
`Transaction not confirmed after ${timeoutMs}ms. ` +
|
|
131
|
+
`Hash: ${txHash}. Check block explorer for status.`
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Nonce manager for handling concurrent transactions
|
|
140
|
+
*/
|
|
141
|
+
export class NonceManager {
|
|
142
|
+
private pendingNonces = new Map<string, number>();
|
|
143
|
+
private provider: JsonRpcProvider;
|
|
144
|
+
|
|
145
|
+
constructor(provider: JsonRpcProvider) {
|
|
146
|
+
this.provider = provider;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Get next available nonce for address
|
|
151
|
+
*
|
|
152
|
+
* @param address - Ethereum address
|
|
153
|
+
* @param forceRefresh - Force refresh from chain
|
|
154
|
+
* @returns Next nonce to use
|
|
155
|
+
*/
|
|
156
|
+
async getNextNonce(address: string, forceRefresh: boolean = false): Promise<number> {
|
|
157
|
+
if (forceRefresh) {
|
|
158
|
+
this.pendingNonces.delete(address);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Get latest nonce from chain
|
|
162
|
+
const chainNonce = await this.provider.getTransactionCount(address, 'latest');
|
|
163
|
+
|
|
164
|
+
// Get pending nonce from our tracking
|
|
165
|
+
const pendingNonce = this.pendingNonces.get(address);
|
|
166
|
+
|
|
167
|
+
// Use whichever is higher
|
|
168
|
+
const nextNonce = pendingNonce !== undefined
|
|
169
|
+
? Math.max(chainNonce, pendingNonce)
|
|
170
|
+
: chainNonce;
|
|
171
|
+
|
|
172
|
+
// Reserve this nonce
|
|
173
|
+
this.pendingNonces.set(address, nextNonce + 1);
|
|
174
|
+
|
|
175
|
+
return nextNonce;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Release a nonce (call if transaction fails)
|
|
180
|
+
*
|
|
181
|
+
* @param address - Ethereum address
|
|
182
|
+
* @param nonce - Nonce to release
|
|
183
|
+
*/
|
|
184
|
+
releaseNonce(address: string, nonce: number): void {
|
|
185
|
+
const pending = this.pendingNonces.get(address);
|
|
186
|
+
if (pending === nonce + 1) {
|
|
187
|
+
this.pendingNonces.set(address, nonce);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Clear nonces for address (e.g., after detecting nonce mismatch)
|
|
193
|
+
*
|
|
194
|
+
* @param address - Ethereum address
|
|
195
|
+
*/
|
|
196
|
+
clearNonces(address: string): void {
|
|
197
|
+
this.pendingNonces.delete(address);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Clear all nonces
|
|
202
|
+
*/
|
|
203
|
+
clearAll(): void {
|
|
204
|
+
this.pendingNonces.clear();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Estimate gas with safety margin
|
|
210
|
+
*
|
|
211
|
+
* @param provider - JSON RPC provider
|
|
212
|
+
* @param tx - Transaction parameters
|
|
213
|
+
* @param marginPercent - Safety margin percentage (default: 20%)
|
|
214
|
+
* @returns Gas limit with safety margin
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* ```typescript
|
|
218
|
+
* const gasLimit = await estimateGasWithMargin(provider, {
|
|
219
|
+
* to: '0x...',
|
|
220
|
+
* value: parseEther('1.0'),
|
|
221
|
+
* data: '0x...'
|
|
222
|
+
* }, 20); // 20% margin
|
|
223
|
+
* ```
|
|
224
|
+
*/
|
|
225
|
+
export async function estimateGasWithMargin(
|
|
226
|
+
provider: JsonRpcProvider,
|
|
227
|
+
tx: any,
|
|
228
|
+
marginPercent: number = 20
|
|
229
|
+
): Promise<bigint> {
|
|
230
|
+
try {
|
|
231
|
+
const estimate = await provider.estimateGas(tx);
|
|
232
|
+
|
|
233
|
+
// Add safety margin
|
|
234
|
+
const margin = (estimate * BigInt(marginPercent)) / 100n;
|
|
235
|
+
const withMargin = estimate + margin;
|
|
236
|
+
|
|
237
|
+
// Cap at block gas limit (if available)
|
|
238
|
+
try {
|
|
239
|
+
const block = await provider.getBlock('latest');
|
|
240
|
+
if (block && block.gasLimit) {
|
|
241
|
+
const blockGasLimit = BigInt(block.gasLimit.toString());
|
|
242
|
+
return withMargin > blockGasLimit ? blockGasLimit : withMargin;
|
|
243
|
+
}
|
|
244
|
+
} catch (error) {
|
|
245
|
+
// If we can't get block, just return withMargin
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return withMargin;
|
|
249
|
+
} catch (error: any) {
|
|
250
|
+
// If estimation fails, return a conservative default
|
|
251
|
+
console.warn('Gas estimation failed, using conservative default:', error.message);
|
|
252
|
+
|
|
253
|
+
// Default gas limits for different transaction types
|
|
254
|
+
if (tx.data && tx.data !== '0x' && tx.data.length > 2) {
|
|
255
|
+
return 500000n; // Contract interaction
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return 21000n; // Simple transfer
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Calculate maximum transaction amount accounting for gas fees
|
|
264
|
+
*
|
|
265
|
+
* @param balance - Available balance
|
|
266
|
+
* @param gasLimit - Estimated gas limit
|
|
267
|
+
* @param gasPrice - Gas price (for legacy) or maxFeePerGas (for EIP-1559)
|
|
268
|
+
* @returns Maximum transferable amount
|
|
269
|
+
*
|
|
270
|
+
* @example
|
|
271
|
+
* ```typescript
|
|
272
|
+
* const balance = await provider.getBalance(address);
|
|
273
|
+
* const gasLimit = 21000n;
|
|
274
|
+
* const gasPrice = (await provider.getFeeData()).gasPrice;
|
|
275
|
+
*
|
|
276
|
+
* const maxAmount = calculateMaxTransferAmount(balance, gasLimit, gasPrice);
|
|
277
|
+
* ```
|
|
278
|
+
*/
|
|
279
|
+
export function calculateMaxTransferAmount(
|
|
280
|
+
balance: bigint,
|
|
281
|
+
gasLimit: bigint,
|
|
282
|
+
gasPrice: bigint
|
|
283
|
+
): bigint {
|
|
284
|
+
const gasCost = gasLimit * gasPrice;
|
|
285
|
+
|
|
286
|
+
if (balance <= gasCost) {
|
|
287
|
+
return 0n;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return balance - gasCost;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Check if transaction has sufficient gas
|
|
295
|
+
*
|
|
296
|
+
* @param balance - Available balance
|
|
297
|
+
* @param amount - Amount to transfer
|
|
298
|
+
* @param gasLimit - Gas limit
|
|
299
|
+
* @param gasPrice - Gas price
|
|
300
|
+
* @returns true if sufficient, throws error otherwise
|
|
301
|
+
* @throws Error if insufficient gas
|
|
302
|
+
*/
|
|
303
|
+
export function checkSufficientGas(
|
|
304
|
+
balance: bigint,
|
|
305
|
+
amount: bigint,
|
|
306
|
+
gasLimit: bigint,
|
|
307
|
+
gasPrice: bigint
|
|
308
|
+
): boolean {
|
|
309
|
+
const gasCost = gasLimit * gasPrice;
|
|
310
|
+
const totalCost = amount + gasCost;
|
|
311
|
+
|
|
312
|
+
if (totalCost > balance) {
|
|
313
|
+
const shortfall = totalCost - balance;
|
|
314
|
+
throw new Error(
|
|
315
|
+
`Insufficient balance for transaction + gas. ` +
|
|
316
|
+
`Need: ${totalCost}, Have: ${balance}, Short: ${shortfall}`
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return true;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Transaction builder with validation
|
|
325
|
+
*/
|
|
326
|
+
export class TransactionBuilder {
|
|
327
|
+
private tx: any = {};
|
|
328
|
+
|
|
329
|
+
constructor(private provider: JsonRpcProvider) {}
|
|
330
|
+
|
|
331
|
+
to(address: string): this {
|
|
332
|
+
this.tx.to = address;
|
|
333
|
+
return this;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
value(amount: bigint): this {
|
|
337
|
+
this.tx.value = amount;
|
|
338
|
+
return this;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
data(data: string): this {
|
|
342
|
+
this.tx.data = data;
|
|
343
|
+
return this;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
gasLimit(limit: bigint): this {
|
|
347
|
+
this.tx.gasLimit = limit;
|
|
348
|
+
return this;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
gasPrice(price: bigint): this {
|
|
352
|
+
this.tx.gasPrice = price;
|
|
353
|
+
return this;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
maxFeePerGas(fee: bigint): this {
|
|
357
|
+
this.tx.maxFeePerGas = fee;
|
|
358
|
+
return this;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
maxPriorityFeePerGas(fee: bigint): this {
|
|
362
|
+
this.tx.maxPriorityFeePerGas = fee;
|
|
363
|
+
return this;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
nonce(nonce: number): this {
|
|
367
|
+
this.tx.nonce = nonce;
|
|
368
|
+
return this;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Build transaction with validation
|
|
373
|
+
*/
|
|
374
|
+
async build(options?: {
|
|
375
|
+
addGasMargin?: boolean;
|
|
376
|
+
marginPercent?: number;
|
|
377
|
+
}): Promise<any> {
|
|
378
|
+
// Validate required fields
|
|
379
|
+
if (!this.tx.to) {
|
|
380
|
+
throw new Error('Transaction must have a "to" address');
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Add gas limit if not provided
|
|
384
|
+
if (!this.tx.gasLimit && options?.addGasMargin) {
|
|
385
|
+
this.tx.gasLimit = await estimateGasWithMargin(
|
|
386
|
+
this.provider,
|
|
387
|
+
this.tx,
|
|
388
|
+
options.marginPercent
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
return { ...this.tx };
|
|
393
|
+
}
|
|
394
|
+
}
|
package/utils/types.ts
CHANGED
|
@@ -270,6 +270,106 @@ export interface Balance {
|
|
|
270
270
|
decimal: number
|
|
271
271
|
}
|
|
272
272
|
|
|
273
|
+
// ============================================
|
|
274
|
+
// Wallet Discovery Types
|
|
275
|
+
// ============================================
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* A discovered wallet with balance information
|
|
279
|
+
*/
|
|
280
|
+
export interface DiscoveredWallet {
|
|
281
|
+
/** BIP-44 account index */
|
|
282
|
+
index: number;
|
|
283
|
+
|
|
284
|
+
/** Wallet address */
|
|
285
|
+
address: string;
|
|
286
|
+
|
|
287
|
+
/** Full BIP-44 derivation path */
|
|
288
|
+
derivationPath: string;
|
|
289
|
+
|
|
290
|
+
/** Native token balance */
|
|
291
|
+
nativeBalance: {
|
|
292
|
+
amount: bigint; // Raw amount (wei, lamports)
|
|
293
|
+
formatted: number; // Human-readable (ETH, SOL)
|
|
294
|
+
symbol: string; // 'ETH', 'SOL', etc.
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
/** Optional: Include private key (security consideration) */
|
|
298
|
+
privateKey?: string;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Discovery options
|
|
303
|
+
*/
|
|
304
|
+
export interface WalletDiscoveryOptions {
|
|
305
|
+
/** Starting index (default: 0) */
|
|
306
|
+
startIndex?: number;
|
|
307
|
+
|
|
308
|
+
/** Maximum index to check (default: 100) */
|
|
309
|
+
maxIndex?: number;
|
|
310
|
+
|
|
311
|
+
/** Gap limit - stop after N empty wallets (default: 20) */
|
|
312
|
+
gapLimit?: number;
|
|
313
|
+
|
|
314
|
+
/** Minimum balance to consider (default: 0) */
|
|
315
|
+
minBalance?: bigint;
|
|
316
|
+
|
|
317
|
+
/** Include wallets with zero balance (default: false) */
|
|
318
|
+
includeZeroBalance?: boolean;
|
|
319
|
+
|
|
320
|
+
/** Include private keys in results (default: false) */
|
|
321
|
+
includePrivateKeys?: boolean;
|
|
322
|
+
|
|
323
|
+
/** Check wallets in parallel (default: true for speed) */
|
|
324
|
+
checkInParallel?: boolean;
|
|
325
|
+
|
|
326
|
+
/** If parallel, batch size (default: 10) */
|
|
327
|
+
batchSize?: number;
|
|
328
|
+
|
|
329
|
+
/** Delay between checks in milliseconds (default: 200ms for parallel, 50ms for sequential) */
|
|
330
|
+
checkDelay?: number;
|
|
331
|
+
|
|
332
|
+
/** Progress callback */
|
|
333
|
+
onProgress?: (current: number, total: number, found: number) => void;
|
|
334
|
+
|
|
335
|
+
/** Callback when a wallet is discovered */
|
|
336
|
+
onDiscovered?: (wallet: DiscoveredWallet) => void;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Pocket discovery options
|
|
341
|
+
*/
|
|
342
|
+
export interface PocketDiscoveryOptions extends Omit<WalletDiscoveryOptions, 'onDiscovered'> {
|
|
343
|
+
/** Wallet index for pocket derivation (default: 0) */
|
|
344
|
+
walletIndex?: number;
|
|
345
|
+
|
|
346
|
+
/** Callback when a pocket is discovered */
|
|
347
|
+
onDiscovered?: (pocket: DiscoveredWallet) => void;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Discovery result
|
|
352
|
+
*/
|
|
353
|
+
export interface WalletDiscoveryResult {
|
|
354
|
+
/** Discovered wallets with balances */
|
|
355
|
+
discovered: DiscoveredWallet[];
|
|
356
|
+
|
|
357
|
+
/** Number of indices scanned */
|
|
358
|
+
scannedIndices: number;
|
|
359
|
+
|
|
360
|
+
/** Highest index checked */
|
|
361
|
+
highestIndex: number;
|
|
362
|
+
|
|
363
|
+
/** Total balance across all discovered wallets */
|
|
364
|
+
totalBalance: bigint;
|
|
365
|
+
|
|
366
|
+
/** Whether scan was stopped by gap limit */
|
|
367
|
+
stoppedByGapLimit: boolean;
|
|
368
|
+
|
|
369
|
+
/** Scan duration in milliseconds */
|
|
370
|
+
duration: number;
|
|
371
|
+
}
|
|
372
|
+
|
|
273
373
|
|
|
274
374
|
export const SUPPORTED_VM = {
|
|
275
375
|
'EVM': EVMVM,
|