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.
@@ -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
+ }