ethershell 0.2.5-beta.0 → 0.2.6-beta.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/README.md CHANGED
@@ -13,19 +13,19 @@ An interactive Node.js console for Ethereum smart contract development. Write, c
13
13
 
14
14
  ## ✨ Features
15
15
 
16
- - **Interactive REPL Shell** - Built-in async support for all commands with custom evaluation
17
- - **Solidity Compilation** - Compile contracts with configurable optimization and viaIR mode
18
- - **Smart Contract Deployment** - Deploy contracts to any EVM network
19
- - **Wallet Management** - Create, import, and manage wallets (regular & HD wallets, node-managed accounts)
20
- - **Multi-Network Support** - Switch between different blockchain networks with persistent configuration
21
- - **Contract Proxy Wrapper** - Enhanced contract interaction with flexible transaction options (from, value, gasLimit, maxFeePerGas, etc.)
22
- - **Contract Interactions** - Call contract methods with advanced options directly from the shell
23
- - **ABI & Bytecode Generation** - Organized artifact output with metadata
24
- - **Node Signer Integration** - Connect to node-managed accounts (Ganache, Hardhat)
25
- - **TypeScript Code Generation** - Auto-generate TypeScript types from contract ABIs
26
- - **Gas Optimization** - Configure compiler optimization levels and viaIR code generation
27
- - **Persistent Configuration** - Save and restore network, compiler, and wallet settings
28
- - **Comprehensive JSDoc** - Full IDE autocomplete and type hints
16
+ - **Interactive REPL Shell** Custom async evaluation with top‑level `await` support in a Node.js REPL.
17
+ - **Solidity Compilation** Compile contracts with configurable optimization and `viaIR` options.
18
+ - **Smart Contract Deployment** Deploy contracts to any EVM network using ethers v6.
19
+ - **Wallet Management** Create, import, and manage wallets (regular & HD wallets, plus nodemanaged accounts).
20
+ - **MultiNetwork Support** Switch between blockchain networks with persistent provider configuration.
21
+ - **Contract Proxy Wrapper** Enhanced contract interaction with a proxy that supports `from`, `value`, gas options, EIP‑1559 fields, and custom data.
22
+ - **Contract Interactions** Call contract methods (read & write) with advanced options directly from the shell.
23
+ - **ABI & Bytecode Generation** Organized artifacts (`artifacts`, `abis`, `bytecode`, `metadata`) plus an aggregated ABI file.
24
+ - **Node Signer Integration** Connect to nodemanaged accounts (Hardhat, Anvil, etc.).
25
+ - **TypeScript Code Generation** Autogenerate TypeScript types from ABIs into a `types/` directory under the build path.
26
+ - **Gas Optimization Controls** Configure optimizer enable flag, runs, and `viaIR` globally.
27
+ - **Persistent Configuration** Store provider, compiler config, wallets, and contracts in the `./ethershell` directory.
28
+ - **Comprehensive JSDoc** Rich JSDoc comments for IDE autocompletion and type hints throughout the codebase.
29
29
 
30
30
  ## 🚀 Quick Start
31
31
 
@@ -36,13 +36,15 @@ An interactive Node.js console for Ethereum smart contract development. Write, c
36
36
  npm i -g ethershell
37
37
 
38
38
  # Start EtherShell in the root directory of your project:
39
- ethershell
39
+ ethershell
40
40
 
41
- #or
41
+ # or
42
42
 
43
43
  npx ethershell
44
44
  ```
45
45
 
46
+ Run the CLI in your project root so EtherShell can find `./contracts` and write `./ethershell` and `./build` data next to your project files.
47
+
46
48
  ### Basic Usage
47
49
 
48
50
  ```bash
@@ -53,11 +55,11 @@ ethershell
53
55
  # EtherShell>
54
56
  ```
55
57
 
56
- ## 📖 Step-by-Step Guide
58
+ ## 📖 StepbyStep Guide
57
59
 
58
60
  ### 1. Network Configuration
59
61
 
60
- First, connect to a blockchain network:
62
+ First, connect to a blockchain network.
61
63
 
62
64
  ```javascript
63
65
  // View current network
@@ -73,6 +75,8 @@ EtherShell> defaultChain()
73
75
  { URL: 'http://127.0.0.1:8545' }
74
76
  ```
75
77
 
78
+ Internally, `chain()` updates the in‑memory provider and saves the selected endpoint to `./ethershell/config.json` so it persists between sessions.
79
+
76
80
  ### 2. Wallet Management
77
81
 
78
82
  #### Create New Wallets
@@ -103,6 +107,8 @@ EtherShell> newWallet(5)
103
107
  ]
104
108
  ```
105
109
 
110
+ `newWallet()` persists wallets into `./ethershell/wallets.json`.
111
+
106
112
  #### Import Existing Wallets
107
113
 
108
114
  ```javascript
@@ -117,6 +123,8 @@ EtherShell> addWallet([
117
123
  ])
118
124
  ```
119
125
 
126
+ EtherShell detects duplicate wallets by private key and throws if you attempt to re‑add an existing key.
127
+
120
128
  #### HD Wallet Management
121
129
 
122
130
  ```javascript
@@ -140,16 +148,16 @@ EtherShell> addHDWallet('word word word ... (12 or 24 words)', 10)
140
148
  EtherShell> hdWallets()
141
149
  !WARNING!
142
150
  The generated accounts are NOT safe. Do NOT use them on main net!
143
- [...]
151
+ [ ... ]
144
152
  ```
145
153
 
146
- #### Connect to Node-Managed Accounts
154
+ #### Connect to NodeManaged Accounts
147
155
 
148
156
  ```javascript
149
- // For Ganache, Hardhat, or other nodes with unlocked accounts
157
+ // For Hardhat, Anvil, or other nodes with unlocked accounts
150
158
  EtherShell> connectWallet()
151
159
 
152
- // This adds accounts managed by the node (e.g., Ganache default accounts)
160
+ // This adds accounts managed by the node (e.g., Hardhat default accounts)
153
161
  ```
154
162
 
155
163
  #### View Wallets
@@ -166,7 +174,7 @@ EtherShell> walletInfo(0)
166
174
  // or by address
167
175
  EtherShell> walletInfo('0x1234...5678')
168
176
  // or multiple
169
- EtherShell> walletInfo([0, 1, 2])
177
+ EtherShell> walletInfo()[1][2]
170
178
 
171
179
  // Change default account
172
180
  EtherShell> changeDefWallet(0)
@@ -189,39 +197,47 @@ EtherShell> removeWallet('0x1234...5678')
189
197
  EtherShell> removeWallet('word word word ...')
190
198
 
191
199
  // Delete multiple by indices
192
- EtherShell> removeWallet([0, 2, 4])
200
+ EtherShell> removeWallet()[2][3]
193
201
 
194
202
  // Delete all wallets
195
203
  EtherShell> removeWallet()
196
204
  ```
197
205
 
206
+ Deletion updates in‑memory arrays and rewrites `./ethershell/wallets.json`; if the removed wallet is the default one, the default entry in `config.json` is also cleared.
207
+
198
208
  ### 3. Solidity Compilation
199
209
 
200
210
  #### Configure Compiler
201
211
 
202
212
  ```javascript
203
- // View current compiler version
213
+ // View current compiler version (bundled solc if no remote has been loaded)
204
214
  EtherShell> compiler()
205
- "0.8.20+commit.a1b79de6.Emscripten.clang"
215
+ "0.8.xx+commit....Emscripten.clang"
206
216
 
207
217
  // Switch to a different Solidity version
208
- EtherShell> compUpdate('v0.8.19+commit.7dd6d404')
209
- Loaded solc version: 0.8.19+commit.7dd6d404.Emscripten.clang
218
+ EtherShell> compUpdate('v0.8.29+commit.ab55807c')
219
+ Loaded solc version: 0.8.29+commit.ab55807c.Emscripten.clang
210
220
 
211
221
  // Configure compilation options (gasOptimizer, viaIR, optimizerRuns)
212
222
  EtherShell> compOpts(true, false, 1000)
213
223
  ✓ Compiler options updated:
214
224
  Gas Optimizer: Enabled
215
- Optimizer Runs: 1000
216
225
  ViaIR: Disabled
226
+ Optimizer Runs: 1000
217
227
 
218
- // Get current options
228
+ // Get current compiler options
219
229
  EtherShell> compInfo()
220
- { optimizer: true, optimizerRuns: 1000, viaIR: false }
230
+ {
231
+ version: 'v0.8.29+commit.ab55807c',
232
+ optimizer: true,
233
+ viaIR: false,
234
+ optimizerRuns: 1000,
235
+ compilePath: './build'
236
+ }
221
237
 
222
238
  // Get current config info
223
239
  EtherShell> configInfo()
224
- {
240
+ {
225
241
  providerEndpoint: '...',
226
242
  defaultWallet: { ... },
227
243
  compiler: {
@@ -241,37 +257,45 @@ EtherShell> defWallet()
241
257
  EtherShell> compPath('./custom-build')
242
258
  ```
243
259
 
260
+ Compiler configuration is kept in memory and mirrored into `config.json`, including version, optimizer flags, runs, and the default `compilePath`.
261
+
244
262
  #### Compile Contracts
245
263
 
246
264
  ```javascript
247
265
  // Compile all .sol files in ./contracts directory
248
266
  EtherShell> build()
249
267
  Contracts compiled into /path/to/build
268
+ Aggregated ABI generated at /path/to/build/aggregated.abi.json
250
269
  TypeScript types generated in /path/to/build/types
251
270
 
252
271
  // Compile a specific contract file
253
272
  EtherShell> build('./contracts/MyToken.sol')
254
273
  Contract compiled into /path/to/build
255
274
 
256
- // Compile specific contracts from a file
275
+ // Compile specific contracts from a file to a custom build directory
257
276
  EtherShell> build('./contracts/MyToken.sol', ['MyToken', 'OtherContract'], './custom-build')
258
277
  Contracts compiled into /path/to/custom-build
259
278
 
260
279
  // Clean build directory
261
280
  EtherShell> clean()
262
281
  Directory deleted successfully
263
- ```
282
+ ```
264
283
 
265
284
  **Compiler Output Structure:**
266
- ```
285
+
286
+ ```text
267
287
  build/
268
- ├── artifacts/ # Complete contract data with metadata
269
- ├── abis/ # Contract ABIs (.abi.json files)
270
- ├── bytecode/ # Contract bytecode (.bin files)
271
- ├── metadata/ # Contract metadata (.metadata.json files)
272
- └── types/ # Auto-generated TypeScript types
288
+ ├── artifacts/ # Complete contract data with metadata
289
+ ├── abis/ # Contract ABIs (.abi.json files)
290
+ ├── bytecode/ # Contract bytecode (.bin files)
291
+ ├── metadata/ # Contract metadata (.metadata.json files)
292
+ ├── standard-json/ # Per‑entry solc standard JSON inputs
293
+ ├── aggregated.abi.json # Flattened ABI array from all ABI files
294
+ └── types/ # Auto-generated TypeScript types
273
295
  ```
274
296
 
297
+ TypeScript types are generated by scanning `build/abis` and writing `.ts` files plus an `index.ts` barrel export.
298
+
275
299
  ### 4. Smart Contract Deployment
276
300
 
277
301
  #### Deploy New Contracts
@@ -294,50 +318,29 @@ EtherShell> deploy('contractName')
294
318
  // Deploy MyToken contract with constructor args and default wallet
295
319
  // Arguments: contractName, args[], walletIndex, [chainURL], [abiLocation], [bytecodeLocation]
296
320
  EtherShell> deploy('MyToken', ['MyTokenName', 'MTK', 1000000])
297
- {
298
- hash: '0x123abc...',
299
- from: '0x1234...5678',
300
- to: null,
301
- address: '0xabcd...ef01',
302
- name: 'MyToken',
303
- chain: 'sepolia',
304
- chainId: 11155111n,
305
- deployType: 'ethershell-deployed'
306
- }
321
+ { ... }
307
322
 
308
323
  // Deploy MyToken contract with constructor args and a non-default wallet
309
- // Arguments: contractName, args[], walletIndex, [chainURL], [abiLocation], [bytecodeLocation]
310
324
  EtherShell> deploy('MyToken', ['MyTokenName', 'MTK', 1000000], 0)
311
- {
312
- hash: '0x123abc...',
313
- from: '0x1234...5678',
314
- to: null,
315
- address: '0xabcd...ef01',
316
- name: 'MyToken',
317
- chain: 'sepolia',
318
- chainId: 11155111n,
319
- deployType: 'ethershell-deployed'
320
- }
325
+ { ... }
321
326
 
322
327
  // Deploy with custom chain
323
328
  EtherShell> deploy('MyContract', ['arg1', 'arg2'], 0, 'https://custom-rpc.url')
324
-
325
- // The deployed contract is automatically added to console context as a proxy
326
- EtherShell> MyToken
327
- Contract {
328
- target: '0xabcd...ef01',
329
- interface: Interface { ... },
330
- runner: Signer { ... },
331
- // ... contract methods available
332
- }
333
329
  ```
334
330
 
331
+ ABIs and bytecode are resolved from the build directory via paths persisted in `./ethershell` local storage,.
332
+
335
333
  #### Add Existing Contracts
336
334
 
337
335
  ```javascript
338
336
  // Add an already-deployed contract
339
337
  // Arguments: contractName, contractAddress, walletIndex, abiPath, [chainURL]
340
- EtherShell> addContract('USDT', '0xdAC17F958D2ee523a2206206994597C13D831ec7', 0, './abis/USDT.json')
338
+ EtherShell> addContract(
339
+ 'USDT',
340
+ '0xdAC17F958D2ee523a2206206994597C13D831ec7',
341
+ 0,
342
+ './build/abis/USDT.abi.json'
343
+ )
341
344
  {
342
345
  index: 1,
343
346
  name: 'USDT',
@@ -347,11 +350,13 @@ EtherShell> addContract('USDT', '0xdAC17F958D2ee523a2206206994597C13D831ec7', 0,
347
350
  deployType: 'pre-deployed'
348
351
  }
349
352
 
350
- // Now you can interact with it
353
+ // Now you can interact with it:
351
354
  EtherShell> USDT.balanceOf('0x1234...5678')
352
- n
355
+ 1000000000000000000n
353
356
  ```
354
357
 
358
+ All added/deployed contracts are also stored in `./ethershell/contracts.json`.
359
+
355
360
  ### 5. Contract Interaction
356
361
 
357
362
  #### View Contracts
@@ -387,6 +392,7 @@ EtherShell> contracts('0xabcd...ef01')
387
392
  EtherShell> contracts('MyToken')
388
393
  ```
389
394
 
395
+ `contracts()` reads enriched contract information (including live balances).
390
396
  #### Call Contract Functions
391
397
 
392
398
  ```javascript
@@ -394,50 +400,43 @@ EtherShell> contracts('MyToken')
394
400
  EtherShell> MyToken
395
401
  Contract { ... }
396
402
 
397
- // Read-only functions (no gas cost)
403
+ // Read-only functions
398
404
  EtherShell> MyToken.name()
399
405
  "MyTokenName"
400
406
 
401
407
  EtherShell> MyToken.totalSupply()
402
408
  1000000n
403
409
 
404
- // State-changing functions (costs gas, requires signer)
410
+ // State-changing functions
405
411
  EtherShell> MyToken.transfer('0xRecipientAddress', 100)
406
- ContractTransactionResponse { ... }
412
+ ContractTransactionReceipt { ... }
407
413
 
408
414
  // Call with advanced transaction options
409
415
  EtherShell> MyToken.transfer('0xRecipientAddress', 100, {
410
- from: '0xSenderAddress', // Switch signer
411
- value: 10000000000000n, // Send ETH (for payable functions)
412
- gasLimit: 500000, // Custom gas limit
413
- maxFeePerGas: 100000000000n, // EIP-1559
416
+ from: '0xSenderAddress', // Switch signer (must be a non node-managed wallet)
417
+ value: 10000000000000n, // Send ETH (payable)
418
+ gasLimit: 500000,
419
+ maxFeePerGas: 100000000000n,
414
420
  maxPriorityFeePerGas: 2000000000n,
415
421
  nonce: 42,
416
422
  chainId: 1
417
423
  })
418
-
419
- // Check balance
420
- EtherShell> MyToken.balanceOf('0x1234...5678')
421
- 100n
422
424
  ```
423
425
 
424
- **Contract Proxy Options:**
425
- The contract proxy wrapper supports these transaction options:
426
- - `from`: Change the signer/sender for the transaction
427
- - `value`: ETH amount to send (for payable functions)
428
- - `gasLimit` / `gas`: Maximum gas to use
429
- - `gasPrice`: Legacy transaction gas price
430
- - `maxFeePerGas`: EIP-1559 max fee per gas
431
- - `maxPriorityFeePerGas`: EIP-1559 priority fee per gas
432
- - `nonce`: Transaction nonce for ordering
433
- - `chainId`: Network chain ID
434
- - `accessList`: EIP-2930 access list
435
- - `type`: Transaction type (0, 1, 2, or 3)
436
- - `customData`: Custom data for special networks (zkSync)
426
+ **Contract Proxy Options include:**
437
427
 
438
- ## 🎯 Complete Usage Example
428
+ - `from`: change signer (must have `privateKey`)
429
+ - `value`: ETH value for payable functions
430
+ - `gasLimit` or `gas`
431
+ - `gasPrice`
432
+ - `maxFeePerGas`, `maxPriorityFeePerGas`
433
+ - `nonce`
434
+ - `chainId`
435
+ - `accessList`
436
+ - `type`
437
+ - `customData` for special networks (e.g., zkSync)[file:25]
439
438
 
440
- Here's a full workflow example:
439
+ ## 🎯 Complete Usage Example
441
440
 
442
441
  ```javascript
443
442
  // 1. Connect to network
@@ -460,7 +459,6 @@ EtherShell> deploy('MyToken', ['TestToken', 'TEST', 1000000])
460
459
 
461
460
  // 7. Interact with contract
462
461
  EtherShell> MyToken.balanceOf('0x...')
463
- 1000000000000000000000000n
464
462
 
465
463
  // 8. Transfer tokens with custom options
466
464
  EtherShell> tx = MyToken.transfer('0x...', 100, {
@@ -478,129 +476,98 @@ EtherShell> contracts()
478
476
  ## 📋 Command Reference
479
477
 
480
478
  ### Network Commands
481
- | Command | Description |
482
- |---------|-------------|
483
- | `chain(url)` | Connect to blockchain network |
484
- | `chainInfo()` | Get current network info |
485
- | `defaultChain()` | Get default network URL |
479
+
480
+ | Command | Description |
481
+ |------------------|-------------------------------------|
482
+ | `chain(url)` | Connect to blockchain network |
483
+ | `chainInfo()` | Get current network info |
484
+ | `defaultChain()` | Get default network URL |[file:13][file:19]
486
485
 
487
486
  ### Wallet Commands
488
- | Command | Description |
489
- |---------|-------------|
490
- | `newWallet([count])` | Create random wallets |
491
- | `addWallet(privKey\|keys)` | Import wallets from private keys |
492
- | `newHDWallet([count])` | Create HD wallet with random mnemonic |
493
- | `addHDWallet(phrase, count)` | Import HD wallet from mnemonic |
494
- | `connectWallet()` | Connect to node-managed accounts |
495
- | `wallets()` | View regular accounts |
496
- | `hdWallets()` | View HD accounts |
497
- | `allWallets()` | View all accounts |
498
- | `walletInfo(index\|address\|[indices])` | Get wallet details (balance, nonce) |
499
- | `changeDefWallet(pointer)` | Set default account |
500
- | `removeWallet(pointer)` | Delete account(s) |
487
+
488
+ | Command | Description |
489
+ |-------------------------------------------|--------------------------------------------------|
490
+ | `newWallet([count])` | Create random wallets |
491
+ | `addWallet(privKey\|keys)` | Import wallets from private keys |
492
+ | `newHDWallet([count])` | Create HD wallet with random mnemonic |
493
+ | `addHDWallet(phrase, count)` | Import HD wallet from mnemonic |
494
+ | `connectWallet()` | Connect to node‑managed accounts |
495
+ | `wallets()` | View regular accounts |
496
+ | `hdWallets()` | View HD accounts |
497
+ | `allWallets()` | View all accounts |
498
+ | `walletInfo(index\|address\|[indices])` | Get wallet details (balance, nonce) |
499
+ | `changeDefWallet(pointer)` | Set default account |
500
+ | `removeWallet(pointer)` | Delete account(s) |[file:13][file:20][file:22]
501
501
 
502
502
  ### Compiler Commands
503
- | Command | Description |
504
- |---------|-------------|
505
- | `compiler()` | Get current Solidity version |
506
- | `compUpdate(version)` | Load specific Solidity version |
507
- | `compOpts(gasOpt, viaIR, runs)` | Configure optimization |
508
- | `compInfo()` | Get current compiler options |
509
- | `configInfo()` | Get all configuration info |
510
- | `defWallet()` | Get default account |
511
- | `compPath(newPath)` | Change build output path |
512
- | `build([path], [contracts], [output])` | Compile contracts |
513
- | `clean([path])` | Delete build directory |
503
+
504
+ | Command | Description |
505
+ |-------------------------------------------------|------------------------------------------|
506
+ | `compiler()` | Get current Solidity version string |
507
+ | `compUpdate(version)` | Load specific Solidity version |
508
+ | `compOpts(gasOpt, viaIR, runs)` | Configure optimizer and viaIR |
509
+ | `compInfo()` | Get current compiler configuration |
510
+ | `configInfo()` | Get full configuration object |
511
+ | `defWallet()` | Get default account from config |
512
+ | `compPath(newPath)` | Change build output path |
513
+ | `build([path], [contracts], [output])` | Compile contracts |
514
+ | `clean([path])` | Delete build directory (default `./build`) |[file:13][file:16][file:21][file:17]
514
515
 
515
516
  ### Contract Commands
516
- | Command | Description |
517
- |---------|-------------|
518
- | `deploy(name, [args], [index], [chainURL], [abiLocation], [bytecodeLocation])` | Deploy new contract |
519
- | `addContract(name, address, index, abiPath)` | Add existing contract |
520
- | `contracts([pointer])` | List contracts or get specific one |
517
+
518
+ | Command | Description |
519
+ |-------------------------------------------------------------------------|----------------------------------|
520
+ | `deploy(name, [args], [index], [chainURL], [abiLocation], [bytecodeLocation])` | Deploy new contract |
521
+ | `addContract(name, address, index, abiPath, [chainURL])` | Add existing contract |
522
+ | `contracts([pointer])` | List contracts or get a specific one |[file:13][file:15][file:18]
521
523
 
522
524
  ## 🛠️ Setup for Development
523
525
 
524
526
  ### Prerequisites
525
- - Node.js 16+
526
- - npm or yarn
527
- - Basic Solidity knowledge
528
-
529
- ### Development Setup
530
-
531
- ```bash
532
- # Install dev dependencies
533
- npm install --save-dev @types/node typescript
534
527
 
535
- # Run in development mode
536
- npm run dev
528
+ - Node.js 16+
529
+ - npm or yarn
530
+ - Basic Solidity knowledge[file:31]
537
531
 
538
- # Run tests (if available)
539
- npm test
540
- ```
541
532
 
542
533
  ### Project Structure
543
534
 
544
- ```
535
+ ```text
545
536
  ethershell/
546
537
  ├── bin/
547
- │ └── cli.js # Entry point
538
+ │ └── cli.js # REPL entry point
548
539
  ├── src/
549
540
  │ ├── services/
550
- │ │ ├── build.js # Compiler management
551
- │ │ ├── wallet.js # Wallet management
552
- │ │ ├── network.js # Network provider
553
- │ │ ├── addContracts.js # Contract deployment
554
- │ │ ├── contracts.js # Contract retrieval
555
- │ │ ├── config.js # Configuration
556
- │ │ └── files.js # File utilities
541
+ │ │ ├── build.js # Compiler management & build orchestration
542
+ │ │ ├── wallet.js # Wallet management (accounts, HD, node-managed)
543
+ │ │ ├── network.js # Network provider configuration
544
+ │ │ ├── addContracts.js # Deployment & contract registration
545
+ │ │ ├── contracts.js # Contract lookup helper
546
+ │ │ ├── configSync.js # In‑memory <-> config.json synchronization
547
+ │ │ └── files.js # File system utilities (clean build)
557
548
  │ └── utils/
558
- │ ├── builder.js # Compilation engine
559
- │ ├── dir.js # Directory utilities
560
- │ ├── accounter.js # Account utilities
561
- │ ├── contractProxy.js # Contract proxy wrapper
562
- │ ├── contractLister.js # Contract formatting
563
- │ ├── typeGenerator.js # TypeScript type generation
564
- │ ├── replHelper.js # REPL customization
565
- │ ├── serialize.js # BigInt serialization
566
- │ └── configFileUpdate.js # Config utilities
567
- ├── contracts/ # Your Solidity contracts
568
- ├── build/ # Compiled artifacts
569
- ├── localStorage/ # Persistent config and wallet storage
549
+ │ ├── builder.js # Low‑level solc Standard JSON compiler wrapper
550
+ │ ├── dir.js # Directory & import resolution utilities
551
+ │ ├── accounter.js # Account storage and deletion utilities
552
+ │ ├── contractProxy.js # Contract proxy wrapper with tx options
553
+ │ ├── contractLister.js # Contracts registry and balance formatting
554
+ │ ├── typeGenerator.js # TypeScript type generation from ABIs
555
+ │ ├── replHelper.js # REPL customization & async eval
556
+ │ ├── serialize.js # BigInt serialization for JSON
557
+ │ └── configFileUpdate.js # Helper to update provider in config.json
558
+ ├── contracts/ # Your Solidity contracts
559
+ ├── build/ # Compiled artifacts and types (output)
560
+ ├── ethershell/ # Persistent config, wallets, contracts, solc cache
570
561
  └── package.json
571
562
  ```
572
563
 
564
+ `./ethershell` contains `config.json`, `wallets.json`, `contracts.json`, and localStorage data used by the compiler and contract manager.
565
+
573
566
  ## 📚 Example Contracts
574
567
 
575
- ### Simple ERC20 Token
576
-
577
- ```solidity
578
- // contracts/MyToken.sol
579
- pragma solidity ^0.8.20;
580
-
581
- contract MyToken {
582
- string public name = "My Token";
583
- string public symbol = "MTK";
584
- uint8 public decimals = 18;
585
- uint256 public totalSupply = 1000000 * 10 ** uint256(decimals);
586
-
587
- mapping(address => uint256) public balanceOf;
588
- event Transfer(address indexed from, address indexed to, uint256 value);
589
-
590
- constructor() {
591
- balanceOf[msg.sender] = totalSupply;
592
- }
593
-
594
- function transfer(address to, uint256 value) public returns (bool) {
595
- require(to != address(0));
596
- require(balanceOf[msg.sender] >= value);
597
- balanceOf[msg.sender] -= value;
598
- balanceOf[to] += value;
599
- emit Transfer(msg.sender, to, value);
600
- return true;
601
- }
602
- }
603
- ```
568
+ ### Simple ERC20‑Style Token
569
+
570
+ You can keep the existing sample token or plug in OpenZeppelin contracts; EtherShell will handle `@openzeppelin/...` imports as long as they are installed in `node_modules`.
604
571
 
605
572
  ### Deployment Example
606
573
 
@@ -613,7 +580,6 @@ EtherShell> deploy('MyToken')
613
580
 
614
581
  // 3. Interact
615
582
  EtherShell> MyToken.balanceOf('0x...')
616
- 1000000000000000000000000n
617
583
 
618
584
  // 4. Transfer
619
585
  EtherShell> MyToken.transfer('0x...', 100)
@@ -623,17 +589,18 @@ EtherShell> MyToken.transfer('0x...', 100)
623
589
 
624
590
  ### Persistent Storage
625
591
 
626
- EtherShell stores configuration in the `localStorage` directory:
592
+ EtherShell stores runtime data under the `./ethershell` directory in your project root.
627
593
 
628
- ```
629
- localStorage/
630
- ├── config.json # Compiler and network settings
631
- ├── wallets.json # Imported/generated wallets
594
+ ```text
595
+ ethershell/
596
+ ├── config.json # Compiler and network settings + default wallet
597
+ ├── wallets.json # Imported/generated wallets
598
+ └── contracts.json # Registered contracts and metadata
632
599
  ```
633
600
 
634
- ### Configuration File
601
+ Configuration is updated automatically as you change network, compiler options, default wallet, deploy contracts, or add existing contracts.
635
602
 
636
- The `config.json` file contains:
603
+ ### Configuration File Example
637
604
 
638
605
  ```json
639
606
  {
@@ -644,7 +611,7 @@ The `config.json` file contains:
644
611
  "type": "user-generated"
645
612
  },
646
613
  "compiler": {
647
- "version": "v0.8.20+commit.a1b79de6",
614
+ "version": "v0.8.29+commit.ab55807c",
648
615
  "optimizer": false,
649
616
  "viaIR": false,
650
617
  "optimizerRuns": 200,
@@ -653,101 +620,75 @@ The `config.json` file contains:
653
620
  }
654
621
  ```
655
622
 
656
- ### Environment Variables (Optional)
657
-
658
- Create a `.env` file (optional):
659
-
660
- ```env
661
- # Network
662
- RPC_URL=http://127.0.0.1:8545
663
-
664
- # Build
665
- BUILD_PATH=./build
666
-
667
- # Contracts
668
- CONTRACTS_PATH=./contracts
669
-
670
- # Compiler
671
- COMPILER_VERSION=0.8.20+commit.a1b79de6
672
- OPTIMIZER_ENABLED=true
673
- OPTIMIZER_RUNS=200
674
- VIAIR_ENABLED=false
675
- ```
676
-
677
623
  ## 🔒 Security Warnings
678
624
 
679
625
  ⚠️ **IMPORTANT SECURITY NOTES:**
680
626
 
681
- 1. **Never use generated accounts on mainnet** - They are only for testing
682
- 2. **Keep private keys safe** - Don't commit `.env` files or private keys to git
683
- 3. **Use read-only RPCs** - For production, use read-only endpoints
684
- 4. **Test on testnet first** - Always test contracts on Sepolia before mainnet
685
- 5. **Verify contracts on Etherscan** - Always verify production contracts
627
+ 1. Never use generated accounts on mainnet they are for development and testing only.
628
+ 2. Keep private keys secret do not commit wallets or config files containing secrets.
629
+ 3. Use testnets (e.g. Sepolia) for experimentation before going to mainnet.
630
+ 4. Always audit and review your contracts before production deployments.
631
+
632
+ Add to your `.gitignore`:
686
633
 
687
634
  ```bash
688
- # Add to .gitignore
689
635
  .env
690
- .env.local
691
636
  node_modules/
692
637
  build/
693
- localStorage/
638
+ ethershell/
694
639
  *.log
695
640
  ```
696
641
 
697
- ## 🐛 Troubleshooting
642
+ This prevents accidental commits of compiled artifacts and local wallet/config state.
698
643
 
699
- ### Common Issues
644
+ ## 🐛 Troubleshooting
700
645
 
701
646
  **Issue: `Error: Cannot find module 'ethers'`**
647
+
702
648
  ```bash
703
649
  Solution: npm install
704
650
  ```
705
651
 
706
652
  **Issue: `Cannot connect to network`**
707
- ```bash
708
- - Check RPC URL is correct
709
- - Verify network is running (Hardhat, Ganache, etc.)
710
- - Check internet connection for public RPCs
711
- ```
653
+
654
+ - Check the RPC URL passed to `chain()`.[file:19]
655
+ - Verify the network (Hardhat, Ganache, etc.) is running.
656
+ - For public RPCs, check your internet connection and provider limits.
712
657
 
713
658
  **Issue: `Insufficient balance for gas`**
714
- ```bash
715
- - Ensure wallet has enough ETH for gas
716
- - Use testnet faucet for test ETH
717
- - Check gas prices (sepolia is usually cheap)
718
- ```
659
+
660
+ - Ensure the selected wallet has enough ETH for gas.
661
+ - Use testnet faucets when working on Sepolia or other testnets.
719
662
 
720
663
  **Issue: `Contract not found in build artifacts`**
721
- ```bash
722
- - Run build() first
723
- - Check contract names match exactly
724
- - Verify .sol file exists in ./contracts
725
- ```
726
664
 
727
- **Issue: `Cannot use 'from' option with node-managed account`**
728
- ```bash
729
- - Node-managed accounts cannot be used with the 'from' option
730
- - Only imported/generated wallets with private keys support 'from'
731
- - Use .connect() method for node-managed accounts
732
- ```
665
+ - Run `build()` first.[file:16]
666
+ - Check that contract names match exactly.
667
+ - Verify `.sol` files exist under `./contracts`. [file:23]
733
668
 
734
669
  **Issue: `TypeScript types not generated`**
735
- ```bash
736
- - Ensure contracts compiled successfully with build()
737
- - Check ABIs exist in build/abis/ directory
738
- - Look for error messages in the build() output
739
- ```
670
+
671
+ - Ensure compilation succeeded.
672
+ - Confirm ABI files exist under `build/abis`.
673
+ - Check console output for errors thrown by `generateAllTypes()`. [file:16][file:30]
674
+
675
+ **Issue: error about `{ from }` with node‑managed account**
676
+
677
+ - Node‑managed accounts do not have private keys in EtherShell, so `{ from }` cannot rebind them.
678
+ - Import or generate a wallet with a private key and use that address in `from` instead. [file:20][file:25]
740
679
 
741
680
  ## 📖 API Documentation
742
681
 
743
- Full JSDoc documentation is available in the source files. Each file includes:
744
- - @fileoverview - File purpose
745
- - @param - Parameter types and descriptions
746
- - @returns - Return type information
747
- - @throws - Error documentation
748
- - @example - Usage examples
682
+ The source code uses detailed JSDoc comments:
683
+
684
+ - `@fileoverview` file purpose and module description
685
+ - `@param` parameter types and descriptions
686
+ - `@returns` return types
687
+ - `@throws` error conditions
688
+ - `@example` – usage samples[file:13][file:16][file:20][file:25]
689
+
690
+ You can generate static docs with JSDoc if desired:
749
691
 
750
- Generate HTML docs:
751
692
  ```bash
752
693
  npm install -g jsdoc
753
694
  jsdoc src/ -r -d docs/
@@ -755,38 +696,26 @@ jsdoc src/ -r -d docs/
755
696
 
756
697
  ## 🤝 Contributing
757
698
 
758
- Contributions are welcome! Please:
699
+ Contributions are welcome:
759
700
 
760
- 1. Fork the repository
761
- 2. Create a feature branch (`git checkout -b feature/AmazingFeature`)
762
- 3. Commit changes (`git commit -m 'Add AmazingFeature'`)
763
- 4. Push to branch (`git push origin feature/AmazingFeature`)
764
- 5. Open a Pull Request
701
+ 1. Fork the repository.
702
+ 2. Create a feature branch (`git checkout -b feature/AmazingFeature`).
703
+ 3. Commit your changes.
704
+ 4. Push to your branch.
705
+ 5. Open a Pull Request.[file:31]
765
706
 
766
707
  ## 📄 License
767
708
 
768
- This project is licensed under the BUSL-1.1 License - see LICENSE file for details.
709
+ This project is licensed under the BUSL1.1 License see the `LICENSE` file for details. [file:31]
769
710
 
770
711
  ## 💬 Support & Community
771
712
 
772
- - **Issues**: Report bugs on GitHub Issues
773
- - **Discussions**: Ask questions on GitHub Discussions
774
- - **Documentation**: Check the docs/ folder
775
-
776
- ## 🎓 Learning Resources
777
-
778
- - [Solidity Documentation](https://docs.soliditylang.org/)
779
- - [Ethers.js Documentation](https://docs.ethers.org/)
780
- - [Ethereum Development Guide](https://ethereum.org/en/developers/docs/)
781
- - [Hardhat Documentation](https://hardhat.org/docs)
782
-
783
- ## 📞 Contact
784
-
785
- - GitHub: [@yourusername](https://github.com/yourusername)
786
- - Email: your.email@example.com
713
+ - Issues: GitHub Issues
714
+ - Questions: GitHub Discussions
715
+ - Docs: This README and `ethershell-website.html`[file:31][file:32]
787
716
 
788
717
  ---
789
718
 
790
- **Made with ❤️ for Ethereum developers**
719
+ **Made with ❤️ for Ethereum developers.**
791
720
 
792
- Happy coding! 🚀
721
+ Happy hacking! 🚀
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ethershell",
3
3
  "license": "MIT",
4
- "version": "0.2.5-beta.0",
4
+ "version": "0.2.6-beta.0",
5
5
  "description": "Interactive JavaScript console for Ethereum smart contract management",
6
6
  "author": "Alireza Kiakojouri (alirezaethdev@gmail.com)",
7
7
  "repository": {
@@ -111,7 +111,7 @@ export function build(fullPath, selectedContracts, buildPath) {
111
111
  input.settings.viaIR = true;
112
112
  }
113
113
 
114
- // Compile with import callback
114
+ // Compile with import callback (used for anything not in `sources`)
115
115
  const output = JSON.parse(
116
116
  solc.compile(
117
117
  JSON.stringify(input),
@@ -121,7 +121,7 @@ export function build(fullPath, selectedContracts, buildPath) {
121
121
 
122
122
  if (output.errors) {
123
123
  // Filter out warnings, only throw on actual errors
124
- const errors = output.errors.filter(err => err.severity === 'error');
124
+ const errors = output.errors.filter((err) => err.severity === 'error');
125
125
  if (errors.length > 0) {
126
126
  throw errors;
127
127
  }
@@ -133,13 +133,7 @@ export function build(fullPath, selectedContracts, buildPath) {
133
133
  const bytecode = path.join(buildPath, 'bytecode');
134
134
  const metadata = path.join(buildPath, 'metadata');
135
135
  const standardJsonDir = path.join(buildPath, 'standard-json');
136
- const subPaths = [
137
- artifacts,
138
- abis,
139
- bytecode,
140
- metadata,
141
- standardJsonDir,
142
- ];
136
+ const subPaths = [artifacts, abis, bytecode, metadata, standardJsonDir];
143
137
 
144
138
  // Ensure all sub-paths exist
145
139
  subPaths.forEach(check);
@@ -208,6 +202,11 @@ export function extractLoadableVersion(fullVersion) {
208
202
 
209
203
  /*=========================== HELPER =============================*/
210
204
 
205
+ /**
206
+ * Resolve a filesystem path for an import.
207
+ * - Relative imports: resolved from `fromDir`
208
+ * - Package imports (starting with '@'): from project root `node_modules`
209
+ */
211
210
  function resolveImportPath(importPath, fromDir) {
212
211
  if (importPath.startsWith('./') || importPath.startsWith('../')) {
213
212
  return path.resolve(fromDir, importPath);
@@ -218,13 +217,34 @@ function resolveImportPath(importPath, fromDir) {
218
217
  return path.resolve(process.cwd(), 'node_modules', importPath);
219
218
  }
220
219
 
220
+ /**
221
+ * Compute a canonical logical name for Standard JSON "sources".
222
+ *
223
+ * Rules:
224
+ * - If importPath starts with '@', it is anchored at node_modules, so the
225
+ * canonical name is exactly the import string (e.g. '@openzeppelin/...').
226
+ * - Otherwise, it is resolved relative to the parent canonical name.
227
+ */
228
+ function computeCanonicalName(parentCanonical, importPath) {
229
+ // Always anchor @-imports at the package root
230
+ if (importPath.startsWith('@')) {
231
+ return importPath;
232
+ }
233
+
234
+ const parentDir = path.posix.dirname(parentCanonical || '');
235
+ if (!parentDir || parentDir === '.') {
236
+ return path.posix.normalize(importPath);
237
+ }
238
+ return path.posix.normalize(path.posix.join(parentDir, importPath));
239
+ }
240
+
221
241
  /**
222
242
  * Collect all Solidity sources reachable from an entry file and build
223
243
  * a Standard JSON "sources" object with canonical logical names that
224
244
  * match solc's internal resolution.
225
245
  *
226
246
  * @param {string} entryPath - Absolute path to the entry .sol file
227
- * @param {string} logicalEntryName - Initial logical name (e.g. 'Cliff.sol')
247
+ * @param {string} logicalEntryName - Initial logical name (e.g. 'MainVestingWalletCliff.sol')
228
248
  * @returns {Object} Standard JSON "sources" map
229
249
  */
230
250
  function collectSourcesForStandardJson(entryPath, logicalEntryName) {
@@ -259,21 +279,15 @@ function collectSourcesForStandardJson(entryPath, logicalEntryName) {
259
279
 
260
280
  const resolved = resolveImportPath(importPath, path.dirname(absPath));
261
281
 
262
- // Compute child canonical name relative to the parent canonical name,
263
- // using POSIX paths so it behaves the same on Windows and Linux.
264
- const parentDir = path.posix.dirname(canonicalName);
265
- const childCanonicalName =
266
- parentDir === '.'
267
- ? path.posix.normalize(importPath)
268
- : path.posix.normalize(
269
- path.posix.join(parentDir, importPath)
270
- );
282
+ const childCanonicalName = computeCanonicalName(canonicalName, importPath);
271
283
 
272
284
  processFile(resolved, childCanonicalName);
273
285
  }
274
286
  }
275
287
 
276
- const entryCanonicalName = logicalEntryName || path.basename(entryPath);
288
+ const entryCanonicalName = path.posix.normalize(
289
+ logicalEntryName || path.basename(entryPath)
290
+ );
277
291
  processFile(entryPath, entryCanonicalName);
278
292
  return sources;
279
293
  }