ethershell 0.1.0-alpha.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/LICENSE +55 -0
- package/README.md +647 -0
- package/bin/cli.js +88 -0
- package/package.json +49 -0
- package/src/services/addContracts.js +221 -0
- package/src/services/build.js +157 -0
- package/src/services/contracts.js +43 -0
- package/src/services/files.js +40 -0
- package/src/services/network.js +113 -0
- package/src/services/wallet.js +375 -0
- package/src/utils/accounter.js +213 -0
- package/src/utils/builder.js +169 -0
- package/src/utils/contractLister.js +37 -0
- package/src/utils/dir.js +81 -0
- package/src/utils/replHelper.js +45 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Network provider management for Ethereum connections
|
|
3
|
+
* @description Manages JSON-RPC provider connections to Ethereum networks,
|
|
4
|
+
* allowing users to switch between different networks and retrieve network information.
|
|
5
|
+
* @module network
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { ethers } from 'ethers';
|
|
9
|
+
import { LocalStorage } from 'node-localstorage';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Local storage instance for persisting compiler artifacts paths
|
|
13
|
+
* @type {LocalStorage}
|
|
14
|
+
*/
|
|
15
|
+
const localStorage = new LocalStorage('./localStorage');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Default JSON-RPC URL for local Ethereum node
|
|
19
|
+
* @constant {string}
|
|
20
|
+
*/
|
|
21
|
+
const defaultUrl = 'http://127.0.0.1:8545' ;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Currently active network URL
|
|
25
|
+
* @type {string}
|
|
26
|
+
*/
|
|
27
|
+
export let currentUrl;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Ethers.js JSON-RPC provider instance
|
|
31
|
+
* @type {ethers.JsonRpcProvider}
|
|
32
|
+
*/
|
|
33
|
+
export let provider
|
|
34
|
+
|
|
35
|
+
// Initialize provider with default URL
|
|
36
|
+
/**
|
|
37
|
+
* The specific RPC endpoint URL saved on storage before.
|
|
38
|
+
* @type {string}
|
|
39
|
+
*/
|
|
40
|
+
const storedUrl = localStorage.getItem('url');
|
|
41
|
+
if(storedUrl) {
|
|
42
|
+
provider = new ethers.JsonRpcProvider(storedUrl);;
|
|
43
|
+
currentUrl = storedUrl
|
|
44
|
+
} else {
|
|
45
|
+
provider = new ethers.JsonRpcProvider(defaultUrl);
|
|
46
|
+
currentUrl = defaultUrl;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Set a new network provider
|
|
52
|
+
* @async
|
|
53
|
+
* @param {string} url - The JSON-RPC endpoint URL
|
|
54
|
+
* @returns {Promise<void>}
|
|
55
|
+
* @throws {Error} If connection to the network fails
|
|
56
|
+
* @example
|
|
57
|
+
* await set('https://mainnet.infura.io/v3/YOUR-PROJECT-ID');
|
|
58
|
+
*/
|
|
59
|
+
export async function set(url){
|
|
60
|
+
try{
|
|
61
|
+
provider = new ethers.JsonRpcProvider(url);
|
|
62
|
+
currentUrl = url;
|
|
63
|
+
const result = await provider.getNetwork();
|
|
64
|
+
const network = {
|
|
65
|
+
URL: currentUrl,
|
|
66
|
+
name: result.name,
|
|
67
|
+
chainId: result.chainId
|
|
68
|
+
}
|
|
69
|
+
localStorage.setItem('url', url);
|
|
70
|
+
console.log(network);
|
|
71
|
+
}catch(err){
|
|
72
|
+
console.error(err);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Get current network information
|
|
78
|
+
* @async
|
|
79
|
+
* @returns {Promise<void>}
|
|
80
|
+
* @throws {Error} If unable to retrieve network information
|
|
81
|
+
* @example
|
|
82
|
+
* await get(); // Logs: { URL: '...', name: 'mainnet', chainId: 1n }
|
|
83
|
+
*/
|
|
84
|
+
export async function get(){
|
|
85
|
+
try{
|
|
86
|
+
const result = await provider.getNetwork();
|
|
87
|
+
const network = {
|
|
88
|
+
URL: currentUrl,
|
|
89
|
+
name: result.name,
|
|
90
|
+
chainId: result.chainId
|
|
91
|
+
}
|
|
92
|
+
console.log(network);
|
|
93
|
+
}catch(err){
|
|
94
|
+
console.error(err);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Get default network URL
|
|
100
|
+
* @returns {void}
|
|
101
|
+
* @example
|
|
102
|
+
* getDefault(); // Logs: { URL: 'http://127.0.0.1:8545' }
|
|
103
|
+
*/
|
|
104
|
+
export function getDefault(){
|
|
105
|
+
try{
|
|
106
|
+
const result = {
|
|
107
|
+
URL: defaultUrl
|
|
108
|
+
}
|
|
109
|
+
console.log(result);
|
|
110
|
+
}catch(err){
|
|
111
|
+
console.error(err);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Ethereum wallet management utilities
|
|
3
|
+
* @description Manages Ethereum wallets including creation, import, and deletion
|
|
4
|
+
* of both regular wallets and HD (Hierarchical Deterministic) wallets. Supports
|
|
5
|
+
* importing private keys, generating new wallets, and connecting to node-managed accounts.
|
|
6
|
+
* @module wallet
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { ethers } from 'ethers';
|
|
10
|
+
import { provider } from './network.js';
|
|
11
|
+
import {
|
|
12
|
+
deleteByIndex,
|
|
13
|
+
deleteByIndexArr,
|
|
14
|
+
getAccountInfo,
|
|
15
|
+
detectDupWallet
|
|
16
|
+
} from '../utils/accounter.js';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Array containing all accounts (imported, generated, HD, and node-managed)
|
|
20
|
+
* @type {Array<Object>}
|
|
21
|
+
*/
|
|
22
|
+
export let allAccounts = [];
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Array containing only regular accounts (imported and generated)
|
|
26
|
+
* @type {Array<Object>}
|
|
27
|
+
*/
|
|
28
|
+
export let accounts = [];
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Array containing only HD (Hierarchical Deterministic) accounts
|
|
32
|
+
* @type {Array<Object>}
|
|
33
|
+
*/
|
|
34
|
+
export let hdAccounts = [];
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Add accounts from private key(s)
|
|
38
|
+
* @param {string|Array<string>} privKeyArr - Single private key or array of private keys
|
|
39
|
+
* @throws {Error} If no private key is provided
|
|
40
|
+
* @example
|
|
41
|
+
* addAccounts('0x1234...');
|
|
42
|
+
* addAccounts(['0x1234...', '0x5678...']);
|
|
43
|
+
*/
|
|
44
|
+
export function addAccounts(privKeyArr) {
|
|
45
|
+
if(!privKeyArr){
|
|
46
|
+
throw `You need to add at least one private key. If you have no private key you can create new accounts by 'newAccounts()'! `;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if(!privKeyArr.length){
|
|
50
|
+
throw `You need to add at least one private key. If you have no private key you can create new accounts by 'newAccounts()'! `;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const dupWallet = detectDupWallet(privKeyArr);
|
|
54
|
+
|
|
55
|
+
if(dupWallet.status) {
|
|
56
|
+
throw `Wallets may NOT be duplicated! You are adding wallet index ${dupWallet.index} again!`
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const newFrom = allAccounts.length;
|
|
60
|
+
|
|
61
|
+
if(typeof privKeyArr === 'string'){
|
|
62
|
+
const newAccount = new ethers.Wallet(privKeyArr, provider);
|
|
63
|
+
allAccounts.push({
|
|
64
|
+
index: allAccounts.length,
|
|
65
|
+
address: newAccount.address,
|
|
66
|
+
privateKey: privKeyArr,
|
|
67
|
+
type: 'user-imported',
|
|
68
|
+
contracts: []
|
|
69
|
+
});
|
|
70
|
+
accounts.push({
|
|
71
|
+
index: allAccounts.length - 1,
|
|
72
|
+
address: newAccount.address,
|
|
73
|
+
privateKey: privKeyArr,
|
|
74
|
+
type: 'user-imported',
|
|
75
|
+
contracts: []
|
|
76
|
+
});
|
|
77
|
+
console.log(allAccounts[newFrom]);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if(Array.isArray(privKeyArr)){
|
|
81
|
+
privKeyArr.map(privKey => {
|
|
82
|
+
const newAccount = new ethers.Wallet(privKey, provider);
|
|
83
|
+
allAccounts.push({
|
|
84
|
+
index: allAccounts.length,
|
|
85
|
+
address: newAccount.address,
|
|
86
|
+
privateKey: privKey,
|
|
87
|
+
contracts: []
|
|
88
|
+
});
|
|
89
|
+
accounts.push({
|
|
90
|
+
index: allAccounts.length - 1,
|
|
91
|
+
address: newAccount.address,
|
|
92
|
+
privateKey: privKey,
|
|
93
|
+
contracts: []
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
console.log(allAccounts.slice(newFrom));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Add HD wallets from a mnemonic phrase
|
|
103
|
+
* @param {string} phrase - BIP39 mnemonic phrase
|
|
104
|
+
* @param {number} [count=10] - Number of accounts to derive from the mnemonic
|
|
105
|
+
* @example
|
|
106
|
+
* addHD('witch collapse practice feed shame open despair creek road again ice least', 5);
|
|
107
|
+
*/
|
|
108
|
+
export function addHD(phrase, count = 10) {
|
|
109
|
+
const newFrom = allAccounts.length;
|
|
110
|
+
const hdNode = ethers.HDNodeWallet.fromPhrase(phrase);
|
|
111
|
+
|
|
112
|
+
const existingPhrase = allAccounts.find(wallet => wallet.phrase == phrase);
|
|
113
|
+
if(existingPhrase) {
|
|
114
|
+
throw `Error: HD wallet with this mnemonic phrase already exists at index ${existingPhrase.index}!`
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
for (let i = 0; i < count; i++) {
|
|
118
|
+
const hdWallet = hdNode.derivePath(i.toString());
|
|
119
|
+
const dupHDWallet = detectDupWallet(hdWallet.privateKey);
|
|
120
|
+
if(dupHDWallet.status) {
|
|
121
|
+
throw `Error: Wallets may NOT be duplicated! You are adding wallet index ${dupHDWallet.index} again!`
|
|
122
|
+
} else {
|
|
123
|
+
allAccounts.push({
|
|
124
|
+
index: allAccounts.length,
|
|
125
|
+
address: hdWallet.address,
|
|
126
|
+
phrase: hdWallet.mnemonic.phrase,
|
|
127
|
+
privateKey: hdWallet.privateKey,
|
|
128
|
+
type: 'user-imported',
|
|
129
|
+
path: hdWallet.path,
|
|
130
|
+
depth: hdWallet.depth,
|
|
131
|
+
contracts: []
|
|
132
|
+
});
|
|
133
|
+
hdAccounts.push({
|
|
134
|
+
index: allAccounts.length - 1,
|
|
135
|
+
address: hdWallet.address,
|
|
136
|
+
phrase: hdWallet.mnemonic.phrase,
|
|
137
|
+
privateKey: hdWallet.privateKey,
|
|
138
|
+
type: 'user-imported',
|
|
139
|
+
path: hdWallet.path,
|
|
140
|
+
depth: hdWallet.depth,
|
|
141
|
+
contracts: []
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
console.log(`!WARNING!\n The generated accounts are NOT safe. Do NOT use them on main net!`);
|
|
147
|
+
console.log(allAccounts.slice(newFrom));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Create new random accounts
|
|
152
|
+
* @param {number} [count=1] - Number of accounts to create
|
|
153
|
+
* @example
|
|
154
|
+
* createAccounts(3);
|
|
155
|
+
*/
|
|
156
|
+
export function createAccounts(count = 1) {
|
|
157
|
+
const newAccounts = Array.from({length: count}, () => ethers.Wallet.createRandom());
|
|
158
|
+
const newFrom = accounts.length;
|
|
159
|
+
|
|
160
|
+
for(let i = 0; i < newAccounts.length; i++) {
|
|
161
|
+
|
|
162
|
+
allAccounts.push({
|
|
163
|
+
index: allAccounts.length,
|
|
164
|
+
address: newAccounts[i].address,
|
|
165
|
+
privateKey: newAccounts[i].privateKey,
|
|
166
|
+
type: 'user-generated',
|
|
167
|
+
contracts: []
|
|
168
|
+
});
|
|
169
|
+
accounts.push({
|
|
170
|
+
index: allAccounts.length - 1,
|
|
171
|
+
address: newAccounts[i].address,
|
|
172
|
+
privateKey: newAccounts[i].privateKey,
|
|
173
|
+
type: 'user-generated',
|
|
174
|
+
contracts: []
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
}
|
|
178
|
+
console.log(`!WARNING!\n The generated accounts are NOT safe. Do NOT use them on main net!`);
|
|
179
|
+
console.log(allAccounts.slice(newFrom));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Create new HD wallet with random mnemonic
|
|
184
|
+
* @param {number} [count=10] - Number of accounts to derive
|
|
185
|
+
* @example
|
|
186
|
+
* createHD(5);
|
|
187
|
+
*/
|
|
188
|
+
export function createHD(count = 10) {
|
|
189
|
+
const hdNode = ethers.HDNodeWallet.createRandom();
|
|
190
|
+
const newFrom = allAccounts.length;
|
|
191
|
+
|
|
192
|
+
for (let i = 0; i < count; i++) {
|
|
193
|
+
const hdWallet = hdNode.derivePath(i.toString());
|
|
194
|
+
allAccounts.push({
|
|
195
|
+
index: allAccounts.length,
|
|
196
|
+
address: hdWallet.address,
|
|
197
|
+
phrase: hdWallet.mnemonic.phrase,
|
|
198
|
+
privateKey: hdWallet.privateKey,
|
|
199
|
+
type: 'user-generated',
|
|
200
|
+
nonce: 0,
|
|
201
|
+
balance: 0,
|
|
202
|
+
path: hdWallet.path,
|
|
203
|
+
depth: hdWallet.depth,
|
|
204
|
+
contracts: []
|
|
205
|
+
});
|
|
206
|
+
hdAccounts.push({
|
|
207
|
+
index: allAccounts.length - 1,
|
|
208
|
+
address: hdWallet.address,
|
|
209
|
+
phrase: hdWallet.mnemonic.phrase,
|
|
210
|
+
privateKey: hdWallet.privateKey,
|
|
211
|
+
type: 'user-generated',
|
|
212
|
+
nonce: 0,
|
|
213
|
+
balance: 0,
|
|
214
|
+
path: hdWallet.path,
|
|
215
|
+
depth: hdWallet.depth,
|
|
216
|
+
contracts: []
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
console.log(`!WARNING!\n The generated accounts are NOT safe. Do NOT use them on main net!`);
|
|
221
|
+
console.log(allAccounts.slice(newFrom));
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Get all accounts (imported, generated, HD, and node-managed)
|
|
226
|
+
* @example
|
|
227
|
+
* getAllAccounts();
|
|
228
|
+
*/
|
|
229
|
+
export function getAllAccounts() {
|
|
230
|
+
console.log(`!WARNING!\n The generated accounts are NOT safe. Do NOT use them on main net!`);
|
|
231
|
+
console.log(allAccounts);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Get regular accounts (imported and generated only)
|
|
236
|
+
* @example
|
|
237
|
+
* getAccounts();
|
|
238
|
+
*/
|
|
239
|
+
export function getAccounts() {
|
|
240
|
+
console.log(`!WARNING!\n The generated accounts are NOT safe. Do NOT use them on main net!`);
|
|
241
|
+
console.log(accounts);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Get HD accounts only
|
|
246
|
+
* @example
|
|
247
|
+
* getHDAccounts();
|
|
248
|
+
*/
|
|
249
|
+
export function getHDAccounts() {
|
|
250
|
+
console.log(`!WARNING!\n The generated accounts are NOT safe. Do NOT use them on main net!`);
|
|
251
|
+
console.log(hdAccounts);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Delete account(s) by various identifiers
|
|
256
|
+
* @param {number|string|Array<number>|null} accPointer - Account index, address, mnemonic phrase, or array of indices
|
|
257
|
+
* @example
|
|
258
|
+
* deleteAccount(0); // Delete by index
|
|
259
|
+
* deleteAccount('0x1234...'); // Delete by address
|
|
260
|
+
* deleteAccount([0, 2, 5]); // Delete multiple by indices
|
|
261
|
+
* deleteAccount('witch collapse...'); // Delete all accounts from mnemonic
|
|
262
|
+
* deleteAccount(); // Delete all accounts
|
|
263
|
+
*/
|
|
264
|
+
export function deleteAccount(accPointer) {
|
|
265
|
+
if(!accPointer) {
|
|
266
|
+
deleteByIndex(null);
|
|
267
|
+
console.log(allAccounts);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if(typeof accPointer === 'number') {
|
|
271
|
+
deleteByIndex(accPointer);
|
|
272
|
+
console.log(allAccounts);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if(ethers.isAddress(accPointer)) {
|
|
276
|
+
const index = allAccounts.findIndex(wallet => wallet.address === accPointer);
|
|
277
|
+
|
|
278
|
+
if(index !== -1) {
|
|
279
|
+
deleteByIndex(index);
|
|
280
|
+
}
|
|
281
|
+
console.log(allAccounts);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if(Array.isArray(accPointer)) {
|
|
285
|
+
deleteByIndexArr(accPointer);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if(ethers.Mnemonic.isValidMnemonic(accPointer)) {
|
|
289
|
+
|
|
290
|
+
// Find which accounts to be deleted
|
|
291
|
+
const indicesToDelete = [];
|
|
292
|
+
|
|
293
|
+
for(let i = 0; i < allAccounts.length; i++) {
|
|
294
|
+
if(allAccounts[i].phrase === accPointer) {
|
|
295
|
+
indicesToDelete.push(allAccounts[i].index);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Sort in descending order and delete from highest to lowest
|
|
300
|
+
indicesToDelete.sort((a, b) => b - a);
|
|
301
|
+
|
|
302
|
+
// Delete accounts
|
|
303
|
+
for(let i = 0; i < indicesToDelete.length; i++) {
|
|
304
|
+
deleteByIndex(indicesToDelete[i]);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
console.log(allAccounts);
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Connect to node-managed wallets (e.g., from Hardhat node)
|
|
314
|
+
* @async
|
|
315
|
+
* @returns {Promise<void>}
|
|
316
|
+
* @example
|
|
317
|
+
* await connectWallet();
|
|
318
|
+
*/
|
|
319
|
+
export async function connectWallet() {
|
|
320
|
+
try {
|
|
321
|
+
const addressArr = await provider.listAccounts();
|
|
322
|
+
for (let i = 0; i < addressArr.length; i++) {
|
|
323
|
+
const accSigner = await provider.getSigner(addressArr[i].address);
|
|
324
|
+
allAccounts.push({
|
|
325
|
+
index: allAccounts.length,
|
|
326
|
+
address: addressArr[i].address,
|
|
327
|
+
type: 'node-managed', // Indicate this is managed by the node
|
|
328
|
+
signer: accSigner // Store signer reference
|
|
329
|
+
})
|
|
330
|
+
accounts.push({
|
|
331
|
+
index: allAccounts.length - 1,
|
|
332
|
+
address: addressArr[i].address,
|
|
333
|
+
type: 'node-managed', // Indicate this is managed by the node
|
|
334
|
+
signer: accSigner // Store signer reference
|
|
335
|
+
})
|
|
336
|
+
}
|
|
337
|
+
} catch(err) {
|
|
338
|
+
console.error(err);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Get detailed wallet information including balance and nonce
|
|
344
|
+
* @async
|
|
345
|
+
* @param {number|string|Array} accPointer - Account index, address, or array of indices
|
|
346
|
+
* @throws {Error} If input is empty or invalid
|
|
347
|
+
* @example
|
|
348
|
+
* await getWalletInfo(0); // Get info by index
|
|
349
|
+
* await getWalletInfo('0x1234...'); // Get info by address
|
|
350
|
+
* await getWalletInfo([0, 1, 2]); // Get info for multiple accounts
|
|
351
|
+
*/
|
|
352
|
+
export async function getWalletInfo(accPointer) {
|
|
353
|
+
try {
|
|
354
|
+
if(!accPointer && accPointer != 0) {
|
|
355
|
+
throw new Error('Error: Empty input is NOT valid!');
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if(typeof accPointer === 'number') {
|
|
359
|
+
const index = allAccounts.findIndex(wallet => wallet.index == accPointer);
|
|
360
|
+
await getAccountInfo(index);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if(ethers.isAddress(accPointer)) {
|
|
364
|
+
const index = allAccounts.findIndex(wallet => wallet.address == accPointer);
|
|
365
|
+
await getAccountInfo(index);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if(Array.isArray(accPointer)) {
|
|
369
|
+
await getAccountInfo(accPointer);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
} catch(err) {
|
|
373
|
+
console.error(err);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Account management utilities
|
|
3
|
+
* @description Internal utilities for managing account arrays, including deletion
|
|
4
|
+
* and information retrieval. Handles synchronization across multiple account arrays.
|
|
5
|
+
* @module accounter
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { allAccounts, accounts, hdAccounts } from '../services/wallet.js';
|
|
9
|
+
import { provider } from '../services/network.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Delete account(s) by index
|
|
13
|
+
* @param {number|Array<number>|null} index - Account index, array of indices, or null to delete all
|
|
14
|
+
* @returns {void}
|
|
15
|
+
* @example
|
|
16
|
+
* deleteByIndex(0); // Delete account at index 0
|
|
17
|
+
* deleteByIndex([1, 3, 5]); // Delete multiple accounts
|
|
18
|
+
* deleteByIndex(null); // Delete all accounts
|
|
19
|
+
*/
|
|
20
|
+
export function deleteByIndex(index) {
|
|
21
|
+
if (Array.isArray(index)) {
|
|
22
|
+
deleteByIndexArr(index);
|
|
23
|
+
} else if (typeof index === 'number') {
|
|
24
|
+
_deleteBySingIndex(index);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Delete multiple accounts by array of indices
|
|
30
|
+
* @param {Array<number>} indices - Array of account indices to delete
|
|
31
|
+
* @returns {void}
|
|
32
|
+
* @example
|
|
33
|
+
* deleteByIndexArr([0, 2, 4]);
|
|
34
|
+
*/
|
|
35
|
+
export function deleteByIndexArr(indices) {
|
|
36
|
+
if (!indices || !indices.length) {
|
|
37
|
+
console.error('Error: Empty input is NOT valid!');
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Sort indices in descending order to avoid shifting issues
|
|
42
|
+
const sortedIndices = [...indices].sort((a, b) => b - a);
|
|
43
|
+
|
|
44
|
+
// Delete each index from highest to lowest
|
|
45
|
+
for (const index of sortedIndices) {
|
|
46
|
+
_deleteBySingIndex(index);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Get account information including balance and nonce
|
|
52
|
+
* @async
|
|
53
|
+
* @param {number|Array<number>} index - Account index or array of indices
|
|
54
|
+
* @returns {Promise<void>}
|
|
55
|
+
* @example
|
|
56
|
+
* await getAccountInfo(0);
|
|
57
|
+
* await getAccountInfo([0, 1, 2]);
|
|
58
|
+
*/
|
|
59
|
+
export async function getAccountInfo(index) {
|
|
60
|
+
if (Array.isArray(index)) {
|
|
61
|
+
await _getAccArrInfo(index);
|
|
62
|
+
} else if (typeof index === 'number') {
|
|
63
|
+
await _getAccountInfo(index);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Checks if an imported wallet added before or not.
|
|
69
|
+
* @param {string|Array<string>} privKeyArr - Account private key or array of private keys
|
|
70
|
+
* @returns {Object}
|
|
71
|
+
* @example
|
|
72
|
+
* detectDupWallet('0x12cb...');
|
|
73
|
+
* detectDupWallet(['0x12cb...','0x34cd...', ...]);
|
|
74
|
+
*/
|
|
75
|
+
export function detectDupWallet(privKeyArr) {
|
|
76
|
+
if(typeof privKeyArr === 'string') {
|
|
77
|
+
return _findDupWalletByKey(privKeyArr);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if(Array.isArray(privKeyArr)) {
|
|
81
|
+
return _findDupWalletByArr(privKeyArr);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Get information for multiple accounts (internal)
|
|
87
|
+
* @private
|
|
88
|
+
* @async
|
|
89
|
+
* @param {Array<number>} _indices - Array of account indices
|
|
90
|
+
* @returns {Promise<void>}
|
|
91
|
+
*/
|
|
92
|
+
async function _getAccArrInfo(_indices) {
|
|
93
|
+
if (!_indices || !_indices.length) {
|
|
94
|
+
console.error('Error: Empty input is NOT valid!');
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Sort indices in descending order to avoid shifting issues
|
|
99
|
+
const sortedIndices = [..._indices].sort((a, b) => b - a);
|
|
100
|
+
|
|
101
|
+
// Delete each index from highest to lowest
|
|
102
|
+
for (const index of sortedIndices) {
|
|
103
|
+
await _getAccountInfo(index);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Get information for a single account (internal)
|
|
109
|
+
* @private
|
|
110
|
+
* @async
|
|
111
|
+
* @param {number} _index - Account index
|
|
112
|
+
* @returns {Promise<void>}
|
|
113
|
+
*/
|
|
114
|
+
async function _getAccountInfo(_index) {
|
|
115
|
+
const accInfo = allAccounts[_index];
|
|
116
|
+
|
|
117
|
+
accInfo.nonce = await provider.getTransactionCount(accInfo.address);
|
|
118
|
+
accInfo.balance = await provider.getBalance(accInfo.address);
|
|
119
|
+
|
|
120
|
+
console.log(accInfo);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Delete a single account by index (internal implementation)
|
|
125
|
+
* @private
|
|
126
|
+
* @param {number|null} _index - Account index or null to clear all
|
|
127
|
+
* @returns {void}
|
|
128
|
+
*/
|
|
129
|
+
function _deleteBySingIndex(_index) {
|
|
130
|
+
if (_index === null || _index === undefined) {
|
|
131
|
+
// Clear all arrays
|
|
132
|
+
allAccounts.splice(0);
|
|
133
|
+
accounts.splice(0);
|
|
134
|
+
hdAccounts.splice(0);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Find and remove from allAccounts
|
|
139
|
+
const accountIndex = allAccounts.findIndex(acc => acc.index === _index);
|
|
140
|
+
if (accountIndex !== -1) {
|
|
141
|
+
allAccounts.splice(accountIndex, 1);
|
|
142
|
+
|
|
143
|
+
// Update indices in allAccounts
|
|
144
|
+
for (let i = accountIndex; i < allAccounts.length; i++) {
|
|
145
|
+
allAccounts[i].index = i;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Remove from accounts array if it exists there
|
|
149
|
+
const regularIndex = accounts.findIndex(acc => acc.index === _index);
|
|
150
|
+
if (regularIndex !== -1) {
|
|
151
|
+
accounts.splice(regularIndex, 1);
|
|
152
|
+
// Update indices in accounts
|
|
153
|
+
for (let i = regularIndex; i < accounts.length; i++) {
|
|
154
|
+
accounts[i].index = _index;
|
|
155
|
+
_index++;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Remove from hdAccounts array if it exists there
|
|
160
|
+
const hdIndex = hdAccounts.findIndex(acc => acc.index === _index);
|
|
161
|
+
if (hdIndex !== -1) {
|
|
162
|
+
hdAccounts.splice(hdIndex, 1);
|
|
163
|
+
// Update indices in hdAccounts
|
|
164
|
+
for (let i = hdIndex; i < hdAccounts.length; i++) {
|
|
165
|
+
hdAccounts[i].index = _index;
|
|
166
|
+
_index++;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Find a duplicated wallet using passed private key
|
|
174
|
+
* @private
|
|
175
|
+
* @param {string} privKey - Account private key
|
|
176
|
+
* @returns {Object}
|
|
177
|
+
*/
|
|
178
|
+
function _findDupWalletByKey(privKey) {
|
|
179
|
+
const foundWallet = allAccounts.find(wallet => wallet.privateKey == privKey);
|
|
180
|
+
if(foundWallet) {
|
|
181
|
+
return {
|
|
182
|
+
status: true,
|
|
183
|
+
privateKey: privKey,
|
|
184
|
+
index: foundWallet.index
|
|
185
|
+
}
|
|
186
|
+
} else {
|
|
187
|
+
return {
|
|
188
|
+
status: false
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Find a duplicated wallet using passed private key array
|
|
195
|
+
* @private
|
|
196
|
+
* @param {Array<string>} privKeyArr - Account private key array
|
|
197
|
+
* @returns {Object}
|
|
198
|
+
*/
|
|
199
|
+
function _findDupWalletByArr(privKeyArr) {
|
|
200
|
+
for(let i = 0; i < privKeyArr.length; i++) {
|
|
201
|
+
const foundWallet = allAccounts.find(wallet => wallet.privateKey == privKeyArr[i]);
|
|
202
|
+
if(foundWallet) {
|
|
203
|
+
return {
|
|
204
|
+
status: true,
|
|
205
|
+
privateKey: privKeyArr[i],
|
|
206
|
+
index: foundWallet.index
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return {
|
|
211
|
+
status: false
|
|
212
|
+
}
|
|
213
|
+
}
|