ethershell 0.1.1-alpha.15 → 0.1.1-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/LICENSE +21 -55
- package/README.md +177 -32
- package/bin/cli.js +8 -3
- package/package.json +9 -3
- package/src/services/addContracts.js +39 -26
- package/src/services/build.js +53 -26
- package/src/services/config.js +12 -2
- package/src/services/files.js +3 -2
- package/src/services/network.js +8 -11
- package/src/services/wallet.js +60 -3
- package/src/utils/accounter.js +29 -4
- package/src/utils/builder.js +1 -1
- package/src/utils/configFileUpdate.js +7 -0
- package/src/utils/contractProxy.js +162 -0
- package/src/utils/serialize.js +17 -0
- package/src/utils/typeGenerator.js +247 -0
package/LICENSE
CHANGED
|
@@ -1,55 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
Effective on the Change Date, or the fourth anniversary of the first publicly
|
|
24
|
-
available distribution of a specific version of the Licensed Work under this
|
|
25
|
-
License, whichever comes first, the Licensor hereby grants you rights under
|
|
26
|
-
the terms of the Change License, and the rights granted in the paragraph
|
|
27
|
-
above terminate.
|
|
28
|
-
|
|
29
|
-
If your use of the Licensed Work does not comply with the requirements
|
|
30
|
-
currently in effect as described in this License, you must purchase a
|
|
31
|
-
commercial license from the Licensor, its affiliated entities, or authorized
|
|
32
|
-
resellers, or you must refrain from using the Licensed Work.
|
|
33
|
-
|
|
34
|
-
All copies of the original and modified Licensed Work, and derivative works
|
|
35
|
-
of the Licensed Work, are subject to this License. This License applies
|
|
36
|
-
separately for each version of the Licensed Work and the Change Date may vary
|
|
37
|
-
for each version of the Licensed Work released by Licensor.
|
|
38
|
-
|
|
39
|
-
You must conspicuously display this License on each original or modified copy
|
|
40
|
-
of the Licensed Work. If you receive the Licensed Work in original or
|
|
41
|
-
modified form from a third party, the terms and conditions set forth in this
|
|
42
|
-
License apply to your use of that work.
|
|
43
|
-
|
|
44
|
-
Any use of the Licensed Work in violation of this License will automatically
|
|
45
|
-
terminate your rights under this License for the current and all other
|
|
46
|
-
versions of the Licensed Work.
|
|
47
|
-
|
|
48
|
-
This License does not grant you any right in any trademark or logo of
|
|
49
|
-
Licensor or its affiliates (provided that you may use a trademark or logo of
|
|
50
|
-
Licensor as expressly required by this License).
|
|
51
|
-
|
|
52
|
-
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
|
|
53
|
-
AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
|
|
54
|
-
EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
|
|
55
|
-
MERCHANTABILITY,
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Alireza Kiakojouri
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 🔷 EtherShell - Interactive Ethereum Smart Contract Console
|
|
2
2
|
|
|
3
|
-
**⚠️ WARNING: This package is in
|
|
3
|
+
**⚠️ WARNING: This package is in BETA testing. NOT production ready!**
|
|
4
4
|
|
|
5
5
|
An interactive Node.js console for Ethereum smart contract development. Write, compile, deploy, and manage smart contracts directly from the shell with an intuitive, Solidity-focused developer experience.
|
|
6
6
|
|
|
@@ -13,16 +13,19 @@ An interactive Node.js console for Ethereum smart contract development. Write, c
|
|
|
13
13
|
|
|
14
14
|
## ✨ Features
|
|
15
15
|
|
|
16
|
-
- **Interactive Shell** - Built-in async support for all commands
|
|
17
|
-
- **Solidity Compilation** - Compile contracts with configurable optimization
|
|
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
18
|
- **Smart Contract Deployment** - Deploy contracts to any EVM network
|
|
19
|
-
- **Wallet Management** - Create, import, and manage wallets (regular & HD wallets)
|
|
20
|
-
- **Multi-Network Support** - Switch between different blockchain networks
|
|
21
|
-
- **Contract
|
|
22
|
-
- **
|
|
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
|
|
23
24
|
- **Node Signer Integration** - Connect to node-managed accounts (Ganache, Hardhat)
|
|
24
|
-
- **TypeScript
|
|
25
|
-
- **Gas Optimization** - Configure compiler optimization levels
|
|
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
|
|
26
29
|
|
|
27
30
|
## 🚀 Quick Start
|
|
28
31
|
|
|
@@ -164,6 +167,13 @@ EtherShell> walletInfo(0)
|
|
|
164
167
|
EtherShell> walletInfo('0x1234...5678')
|
|
165
168
|
// or multiple
|
|
166
169
|
EtherShell> walletInfo([0, 1, 2])
|
|
170
|
+
|
|
171
|
+
// Change default account
|
|
172
|
+
EtherShell> changeDefWallet(0)
|
|
173
|
+
// or by address
|
|
174
|
+
EtherShell> changeDefWallet('0x1234...5678')
|
|
175
|
+
// or import and set as default in one command
|
|
176
|
+
EtherShell> changeDefWallet('0xPrivateKeyHere')
|
|
167
177
|
```
|
|
168
178
|
|
|
169
179
|
#### Delete Wallets
|
|
@@ -198,7 +208,7 @@ EtherShell> compiler()
|
|
|
198
208
|
EtherShell> compUpdate('v0.8.19+commit.7dd6d404')
|
|
199
209
|
Loaded solc version: 0.8.19+commit.7dd6d404.Emscripten.clang
|
|
200
210
|
|
|
201
|
-
// Configure compilation options
|
|
211
|
+
// Configure compilation options (gasOptimizer, viaIR, optimizerRuns)
|
|
202
212
|
EtherShell> compOpts(true, false, 1000)
|
|
203
213
|
✓ Compiler options updated:
|
|
204
214
|
Gas Optimizer: Enabled
|
|
@@ -208,6 +218,27 @@ EtherShell> compOpts(true, false, 1000)
|
|
|
208
218
|
// Get current options
|
|
209
219
|
EtherShell> compInfo()
|
|
210
220
|
{ optimizer: true, optimizerRuns: 1000, viaIR: false }
|
|
221
|
+
|
|
222
|
+
// Get current config info
|
|
223
|
+
EtherShell> configInfo()
|
|
224
|
+
{
|
|
225
|
+
providerEndpoint: '...',
|
|
226
|
+
defaultWallet: { ... },
|
|
227
|
+
compiler: {
|
|
228
|
+
version: 'v0.8.29+commit.ab55807c',
|
|
229
|
+
optimizer: false,
|
|
230
|
+
viaIR: false,
|
|
231
|
+
optimizerRuns: 200,
|
|
232
|
+
compilePath: './build'
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Get default wallet
|
|
237
|
+
EtherShell> defWallet()
|
|
238
|
+
{ address: '0x...', ... }
|
|
239
|
+
|
|
240
|
+
// Change build output path
|
|
241
|
+
EtherShell> compPath('./custom-build')
|
|
211
242
|
```
|
|
212
243
|
|
|
213
244
|
#### Compile Contracts
|
|
@@ -216,6 +247,7 @@ EtherShell> compInfo()
|
|
|
216
247
|
// Compile all .sol files in ./contracts directory
|
|
217
248
|
EtherShell> build()
|
|
218
249
|
Contracts compiled into /path/to/build
|
|
250
|
+
TypeScript types generated in /path/to/build/types
|
|
219
251
|
|
|
220
252
|
// Compile a specific contract file
|
|
221
253
|
EtherShell> build('./contracts/MyToken.sol')
|
|
@@ -236,7 +268,8 @@ build/
|
|
|
236
268
|
├── artifacts/ # Complete contract data with metadata
|
|
237
269
|
├── abis/ # Contract ABIs (.abi.json files)
|
|
238
270
|
├── bytecode/ # Contract bytecode (.bin files)
|
|
239
|
-
|
|
271
|
+
├── metadata/ # Contract metadata (.metadata.json files)
|
|
272
|
+
└── types/ # Auto-generated TypeScript types
|
|
240
273
|
```
|
|
241
274
|
|
|
242
275
|
### 4. Smart Contract Deployment
|
|
@@ -244,7 +277,35 @@ build/
|
|
|
244
277
|
#### Deploy New Contracts
|
|
245
278
|
|
|
246
279
|
```javascript
|
|
247
|
-
// Deploy
|
|
280
|
+
// Deploy contract without constructor args and with default wallet
|
|
281
|
+
// Arguments: contractName
|
|
282
|
+
EtherShell> deploy('contractName')
|
|
283
|
+
{
|
|
284
|
+
hash: '0x123abc...',
|
|
285
|
+
from: '0x1234...5678',
|
|
286
|
+
to: null,
|
|
287
|
+
address: '0xabcd...ef01',
|
|
288
|
+
name: 'contractName',
|
|
289
|
+
chain: 'sepolia',
|
|
290
|
+
chainId: 11155111n,
|
|
291
|
+
deployType: 'ethershell-deployed'
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Deploy MyToken contract with constructor args and default wallet
|
|
295
|
+
// Arguments: contractName, args[], walletIndex, [chainURL], [abiLocation], [bytecodeLocation]
|
|
296
|
+
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
|
+
}
|
|
307
|
+
|
|
308
|
+
// Deploy MyToken contract with constructor args and a non-default wallet
|
|
248
309
|
// Arguments: contractName, args[], walletIndex, [chainURL], [abiLocation], [bytecodeLocation]
|
|
249
310
|
EtherShell> deploy('MyToken', ['MyTokenName', 'MTK', 1000000], 0)
|
|
250
311
|
{
|
|
@@ -254,13 +315,14 @@ EtherShell> deploy('MyToken', ['MyTokenName', 'MTK', 1000000], 0)
|
|
|
254
315
|
address: '0xabcd...ef01',
|
|
255
316
|
name: 'MyToken',
|
|
256
317
|
chain: 'sepolia',
|
|
318
|
+
chainId: 11155111n,
|
|
257
319
|
deployType: 'ethershell-deployed'
|
|
258
320
|
}
|
|
259
321
|
|
|
260
322
|
// Deploy with custom chain
|
|
261
323
|
EtherShell> deploy('MyContract', ['arg1', 'arg2'], 0, 'https://custom-rpc.url')
|
|
262
324
|
|
|
263
|
-
// The deployed contract is automatically added to console context
|
|
325
|
+
// The deployed contract is automatically added to console context as a proxy
|
|
264
326
|
EtherShell> MyToken
|
|
265
327
|
Contract {
|
|
266
328
|
target: '0xabcd...ef01',
|
|
@@ -304,16 +366,14 @@ EtherShell> contracts()
|
|
|
304
366
|
address: '0xabcd...ef01',
|
|
305
367
|
chain: 'sepolia',
|
|
306
368
|
chainId: 11155111n,
|
|
307
|
-
deployType: 'ethershell-deployed'
|
|
308
|
-
balance: 0n
|
|
369
|
+
deployType: 'ethershell-deployed'
|
|
309
370
|
},
|
|
310
371
|
{
|
|
311
372
|
index: 1,
|
|
312
373
|
name: 'USDT',
|
|
313
374
|
address: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
|
|
314
375
|
chain: 'mainnet',
|
|
315
|
-
deployType: 'pre-deployed'
|
|
316
|
-
balance: 0n
|
|
376
|
+
deployType: 'pre-deployed'
|
|
317
377
|
}
|
|
318
378
|
]
|
|
319
379
|
|
|
@@ -345,11 +405,36 @@ EtherShell> MyToken.totalSupply()
|
|
|
345
405
|
EtherShell> MyToken.transfer('0xRecipientAddress', 100)
|
|
346
406
|
ContractTransactionResponse { ... }
|
|
347
407
|
|
|
408
|
+
// Call with advanced transaction options
|
|
409
|
+
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
|
|
414
|
+
maxPriorityFeePerGas: 2000000000n,
|
|
415
|
+
nonce: 42,
|
|
416
|
+
chainId: 1
|
|
417
|
+
})
|
|
418
|
+
|
|
348
419
|
// Check balance
|
|
349
420
|
EtherShell> MyToken.balanceOf('0x1234...5678')
|
|
350
421
|
100n
|
|
351
422
|
```
|
|
352
423
|
|
|
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)
|
|
437
|
+
|
|
353
438
|
## 🎯 Complete Usage Example
|
|
354
439
|
|
|
355
440
|
Here's a full workflow example:
|
|
@@ -371,21 +456,22 @@ EtherShell> compOpts(true, false, 1000)
|
|
|
371
456
|
EtherShell> build()
|
|
372
457
|
|
|
373
458
|
// 6. Deploy contract
|
|
374
|
-
EtherShell> deploy('MyToken', ['TestToken', 'TEST', 1000000]
|
|
459
|
+
EtherShell> deploy('MyToken', ['TestToken', 'TEST', 1000000])
|
|
375
460
|
|
|
376
461
|
// 7. Interact with contract
|
|
377
462
|
EtherShell> MyToken.balanceOf('0x...')
|
|
463
|
+
1000000000000000000000000n
|
|
378
464
|
|
|
379
|
-
// 8. Transfer tokens
|
|
380
|
-
EtherShell> tx = MyToken.transfer('0x...', 100
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
465
|
+
// 8. Transfer tokens with custom options
|
|
466
|
+
EtherShell> tx = MyToken.transfer('0x...', 100, {
|
|
467
|
+
gasLimit: 100000,
|
|
468
|
+
maxFeePerGas: 50000000000n
|
|
469
|
+
})
|
|
384
470
|
|
|
385
|
-
//
|
|
471
|
+
// 9. Check balance again
|
|
386
472
|
EtherShell> MyToken.balanceOf('0x...')
|
|
387
473
|
|
|
388
|
-
//
|
|
474
|
+
// 10. View all contracts
|
|
389
475
|
EtherShell> contracts()
|
|
390
476
|
```
|
|
391
477
|
|
|
@@ -395,7 +481,7 @@ EtherShell> contracts()
|
|
|
395
481
|
| Command | Description |
|
|
396
482
|
|---------|-------------|
|
|
397
483
|
| `chain(url)` | Connect to blockchain network |
|
|
398
|
-
| `
|
|
484
|
+
| `chainInfo()` | Get current network info |
|
|
399
485
|
| `defaultChain()` | Get default network URL |
|
|
400
486
|
|
|
401
487
|
### Wallet Commands
|
|
@@ -410,6 +496,7 @@ EtherShell> contracts()
|
|
|
410
496
|
| `hdWallets()` | View HD accounts |
|
|
411
497
|
| `allWallets()` | View all accounts |
|
|
412
498
|
| `walletInfo(index\|address\|[indices])` | Get wallet details (balance, nonce) |
|
|
499
|
+
| `changeDefWallet(pointer)` | Set default account |
|
|
413
500
|
| `removeWallet(pointer)` | Delete account(s) |
|
|
414
501
|
|
|
415
502
|
### Compiler Commands
|
|
@@ -419,13 +506,16 @@ EtherShell> contracts()
|
|
|
419
506
|
| `compUpdate(version)` | Load specific Solidity version |
|
|
420
507
|
| `compOpts(gasOpt, viaIR, runs)` | Configure optimization |
|
|
421
508
|
| `compInfo()` | Get current compiler options |
|
|
509
|
+
| `configInfo()` | Get all configuration info |
|
|
510
|
+
| `defWallet()` | Get default account |
|
|
511
|
+
| `compPath(newPath)` | Change build output path |
|
|
422
512
|
| `build([path], [contracts], [output])` | Compile contracts |
|
|
423
513
|
| `clean([path])` | Delete build directory |
|
|
424
514
|
|
|
425
515
|
### Contract Commands
|
|
426
516
|
| Command | Description |
|
|
427
517
|
|---------|-------------|
|
|
428
|
-
| `deploy(name, args, index)` | Deploy new contract |
|
|
518
|
+
| `deploy(name, [args], [index], [chainURL], [abiLocation], [bytecodeLocation])` | Deploy new contract |
|
|
429
519
|
| `addContract(name, address, index, abiPath)` | Add existing contract |
|
|
430
520
|
| `contracts([pointer])` | List contracts or get specific one |
|
|
431
521
|
|
|
@@ -461,15 +551,22 @@ ethershell/
|
|
|
461
551
|
│ │ ├── wallet.js # Wallet management
|
|
462
552
|
│ │ ├── network.js # Network provider
|
|
463
553
|
│ │ ├── addContracts.js # Contract deployment
|
|
464
|
-
│ │
|
|
554
|
+
│ │ ├── contracts.js # Contract retrieval
|
|
555
|
+
│ │ ├── config.js # Configuration
|
|
556
|
+
│ │ └── files.js # File utilities
|
|
465
557
|
│ └── utils/
|
|
466
558
|
│ ├── builder.js # Compilation engine
|
|
467
559
|
│ ├── dir.js # Directory utilities
|
|
468
560
|
│ ├── accounter.js # Account utilities
|
|
561
|
+
│ ├── contractProxy.js # Contract proxy wrapper
|
|
469
562
|
│ ├── contractLister.js # Contract formatting
|
|
470
|
-
│
|
|
563
|
+
│ ├── typeGenerator.js # TypeScript type generation
|
|
564
|
+
│ ├── replHelper.js # REPL customization
|
|
565
|
+
│ ├── serialize.js # BigInt serialization
|
|
566
|
+
│ └── configFileUpdate.js # Config utilities
|
|
471
567
|
├── contracts/ # Your Solidity contracts
|
|
472
568
|
├── build/ # Compiled artifacts
|
|
569
|
+
├── localStorage/ # Persistent config and wallet storage
|
|
473
570
|
└── package.json
|
|
474
571
|
```
|
|
475
572
|
|
|
@@ -512,7 +609,7 @@ contract MyToken {
|
|
|
512
609
|
EtherShell> build('./contracts/MyToken.sol')
|
|
513
610
|
|
|
514
611
|
// 2. Deploy
|
|
515
|
-
EtherShell> deploy('MyToken'
|
|
612
|
+
EtherShell> deploy('MyToken')
|
|
516
613
|
|
|
517
614
|
// 3. Interact
|
|
518
615
|
EtherShell> MyToken.balanceOf('0x...')
|
|
@@ -524,7 +621,39 @@ EtherShell> MyToken.transfer('0x...', 100)
|
|
|
524
621
|
|
|
525
622
|
## ⚙️ Configuration
|
|
526
623
|
|
|
527
|
-
###
|
|
624
|
+
### Persistent Storage
|
|
625
|
+
|
|
626
|
+
EtherShell stores configuration in the `localStorage` directory:
|
|
627
|
+
|
|
628
|
+
```
|
|
629
|
+
localStorage/
|
|
630
|
+
├── config.json # Compiler and network settings
|
|
631
|
+
├── wallets.json # Imported/generated wallets
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
### Configuration File
|
|
635
|
+
|
|
636
|
+
The `config.json` file contains:
|
|
637
|
+
|
|
638
|
+
```json
|
|
639
|
+
{
|
|
640
|
+
"providerEndpoint": "http://127.0.0.1:8545",
|
|
641
|
+
"defaultWallet": {
|
|
642
|
+
"index": 0,
|
|
643
|
+
"address": "0x...",
|
|
644
|
+
"type": "user-generated"
|
|
645
|
+
},
|
|
646
|
+
"compiler": {
|
|
647
|
+
"version": "v0.8.20+commit.a1b79de6",
|
|
648
|
+
"optimizer": false,
|
|
649
|
+
"viaIR": false,
|
|
650
|
+
"optimizerRuns": 200,
|
|
651
|
+
"compilePath": "./build"
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
### Environment Variables (Optional)
|
|
528
657
|
|
|
529
658
|
Create a `.env` file (optional):
|
|
530
659
|
|
|
@@ -542,6 +671,7 @@ CONTRACTS_PATH=./contracts
|
|
|
542
671
|
COMPILER_VERSION=0.8.20+commit.a1b79de6
|
|
543
672
|
OPTIMIZER_ENABLED=true
|
|
544
673
|
OPTIMIZER_RUNS=200
|
|
674
|
+
VIAIR_ENABLED=false
|
|
545
675
|
```
|
|
546
676
|
|
|
547
677
|
## 🔒 Security Warnings
|
|
@@ -552,6 +682,7 @@ OPTIMIZER_RUNS=200
|
|
|
552
682
|
2. **Keep private keys safe** - Don't commit `.env` files or private keys to git
|
|
553
683
|
3. **Use read-only RPCs** - For production, use read-only endpoints
|
|
554
684
|
4. **Test on testnet first** - Always test contracts on Sepolia before mainnet
|
|
685
|
+
5. **Verify contracts on Etherscan** - Always verify production contracts
|
|
555
686
|
|
|
556
687
|
```bash
|
|
557
688
|
# Add to .gitignore
|
|
@@ -593,6 +724,20 @@ Solution: npm install
|
|
|
593
724
|
- Verify .sol file exists in ./contracts
|
|
594
725
|
```
|
|
595
726
|
|
|
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
|
+
```
|
|
733
|
+
|
|
734
|
+
**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
|
+
```
|
|
740
|
+
|
|
596
741
|
## 📖 API Documentation
|
|
597
742
|
|
|
598
743
|
Full JSDoc documentation is available in the source files. Each file includes:
|
|
@@ -644,4 +789,4 @@ This project is licensed under the BUSL-1.1 License - see LICENSE file for detai
|
|
|
644
789
|
|
|
645
790
|
**Made with ❤️ for Ethereum developers**
|
|
646
791
|
|
|
647
|
-
Happy coding! 🚀
|
|
792
|
+
Happy coding! 🚀
|
package/bin/cli.js
CHANGED
|
@@ -16,7 +16,8 @@ import {
|
|
|
16
16
|
currentCompiler,
|
|
17
17
|
compilerOptions,
|
|
18
18
|
getCompilerOptions,
|
|
19
|
-
compile
|
|
19
|
+
compile,
|
|
20
|
+
changeCompPath
|
|
20
21
|
} from '../src/services/build.js';
|
|
21
22
|
import { set, get, getDefault } from '../src/services/network.js';
|
|
22
23
|
import { deleteDirectory } from '../src/services/files.js';
|
|
@@ -30,12 +31,13 @@ import {
|
|
|
30
31
|
addHD,
|
|
31
32
|
getAllAccounts,
|
|
32
33
|
connectWallet,
|
|
33
|
-
getWalletInfo
|
|
34
|
+
getWalletInfo,
|
|
35
|
+
changeDefaultAccount
|
|
34
36
|
} from '../src/services/wallet.js';
|
|
35
37
|
|
|
36
38
|
import { deploy, add } from '../src/services/addContracts.js';
|
|
37
39
|
import { getContracts } from '../src/services/contracts.js';
|
|
38
|
-
import { getConfigInfo } from '../src/services/config.js';
|
|
40
|
+
import { getConfigInfo, getDefaultAccount } from '../src/services/config.js';
|
|
39
41
|
|
|
40
42
|
/**
|
|
41
43
|
* REPL instance for EtherShell interactive environment
|
|
@@ -62,10 +64,13 @@ r.context.compiler = currentCompiler;
|
|
|
62
64
|
r.context.compUpdate = updateCompiler;
|
|
63
65
|
r.context.compInfo = getCompilerOptions;
|
|
64
66
|
r.context.compOpts = compilerOptions;
|
|
67
|
+
r.context.compPath = changeCompPath;
|
|
65
68
|
r.context.build = compile;
|
|
66
69
|
|
|
67
70
|
// Config commands
|
|
68
71
|
r.context.configInfo = getConfigInfo;
|
|
72
|
+
r.context.changeDefWallet = changeDefaultAccount;
|
|
73
|
+
r.context.defWallet = getDefaultAccount;
|
|
69
74
|
|
|
70
75
|
// Clean build folder
|
|
71
76
|
r.context.clean = deleteDirectory;
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ethershell",
|
|
3
|
-
"
|
|
3
|
+
"license": "MIT",
|
|
4
|
+
"version": "0.1.1-beta.0",
|
|
4
5
|
"description": "Interactive JavaScript console for Ethereum smart contract management",
|
|
5
|
-
"license": "BUSL-1.1",
|
|
6
6
|
"author": "Alireza Kiakojouri (alirezaethdev@gmail.com)",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
@@ -45,5 +45,11 @@
|
|
|
45
45
|
"src/",
|
|
46
46
|
"LICENSE",
|
|
47
47
|
"README.md"
|
|
48
|
-
]
|
|
48
|
+
],
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@typechain/ethers-v6": "^0.5.1",
|
|
51
|
+
"@types/node": "^24.10.2",
|
|
52
|
+
"typechain": "^8.3.2",
|
|
53
|
+
"typescript": "^5.9.3"
|
|
54
|
+
}
|
|
49
55
|
}
|
|
@@ -12,12 +12,14 @@ import { provider } from './network.js';
|
|
|
12
12
|
import { allAccounts, accounts, hdAccounts } from './wallet.js';
|
|
13
13
|
import { LocalStorage } from 'node-localstorage';
|
|
14
14
|
import { r } from '../../bin/cli.js';
|
|
15
|
+
import { configFile } from './build.js';
|
|
16
|
+
import { createContractProxy } from '../utils/contractProxy.js';
|
|
15
17
|
|
|
16
18
|
/**
|
|
17
19
|
* Local storage instance for persisting contract metadata
|
|
18
20
|
* @type {LocalStorage}
|
|
19
21
|
*/
|
|
20
|
-
const localStorage = new LocalStorage('./
|
|
22
|
+
const localStorage = new LocalStorage('./ethershell');
|
|
21
23
|
|
|
22
24
|
/**
|
|
23
25
|
* Map of all deployed and added contracts
|
|
@@ -43,6 +45,7 @@ export async function deploy(contractName, args, accIndex, chain, abiLoc, byteco
|
|
|
43
45
|
try {
|
|
44
46
|
let currentProvider;
|
|
45
47
|
let connectedChain;
|
|
48
|
+
let wallet;
|
|
46
49
|
|
|
47
50
|
if(!contractName) {
|
|
48
51
|
throw new Error('Contract name is empty');
|
|
@@ -54,17 +57,17 @@ export async function deploy(contractName, args, accIndex, chain, abiLoc, byteco
|
|
|
54
57
|
throw new Error('Wallet index is out of range');
|
|
55
58
|
}
|
|
56
59
|
|
|
57
|
-
if(!accIndex) {
|
|
58
|
-
accIndex = 0;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
60
|
if(chain) {
|
|
62
61
|
currentProvider = new ethers.JsonRpcProvider(chain);
|
|
63
62
|
} else {
|
|
64
63
|
currentProvider = provider;
|
|
65
64
|
}
|
|
66
65
|
|
|
67
|
-
|
|
66
|
+
if(!accIndex && accIndex !== 0) {
|
|
67
|
+
accIndex = configFile.defaultWallet.index;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
wallet = new ethers.Wallet(allAccounts[accIndex].privateKey, currentProvider);
|
|
68
71
|
connectedChain = await currentProvider.getNetwork();
|
|
69
72
|
|
|
70
73
|
const abiPath = abiLoc || localStorage.getItem(`${contractName}_abi`);
|
|
@@ -104,11 +107,21 @@ export async function deploy(contractName, args, accIndex, chain, abiLoc, byteco
|
|
|
104
107
|
deployTx.deployType = 'ethershell-deployed',
|
|
105
108
|
deployTx.provider = currentProvider;
|
|
106
109
|
|
|
107
|
-
|
|
108
|
-
|
|
110
|
+
//////////////////////////////////
|
|
111
|
+
|
|
112
|
+
// Create contract proxy
|
|
113
|
+
// Get the contract instance from ethers
|
|
114
|
+
const contractAbi = JSON.parse(fs.readFileSync(abiPath, 'utf8'));
|
|
115
|
+
const contractInstance = new ethers.Contract(deployTx.target, contractAbi, wallet);
|
|
109
116
|
|
|
110
|
-
//
|
|
111
|
-
|
|
117
|
+
// Wrap the contract instace with proxy
|
|
118
|
+
const proxiedContract = createContractProxy(contractInstance, currentProvider, allAccounts);
|
|
119
|
+
|
|
120
|
+
// Add to REPL context with proxy
|
|
121
|
+
r.context[contractName] = proxiedContract;
|
|
122
|
+
contracts.set(contractName, proxiedContract);
|
|
123
|
+
|
|
124
|
+
////////////////////////////////////////////
|
|
112
125
|
|
|
113
126
|
const deployHash = deployTx.deploymentTransaction().hash;
|
|
114
127
|
const tx = await provider.getTransaction(deployHash);
|
|
@@ -144,32 +157,38 @@ export async function add(contractName, contractAddr, accIndex, abiLoc, chain) {
|
|
|
144
157
|
try {
|
|
145
158
|
let currentProvider;
|
|
146
159
|
let connectedChain;
|
|
160
|
+
let wallet;
|
|
147
161
|
|
|
148
162
|
if(!contractAddr) {
|
|
149
163
|
throw new Error('Contract address may not be null or undefined!');
|
|
150
164
|
}
|
|
151
165
|
|
|
152
|
-
if(!accIndex) {
|
|
153
|
-
accIndex = 0;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
166
|
if(chain) {
|
|
157
167
|
currentProvider = new ethers.JsonRpcProvider(chain);
|
|
158
168
|
} else {
|
|
159
169
|
currentProvider = provider;
|
|
160
170
|
}
|
|
161
171
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
if(!abiLoc) {
|
|
166
|
-
throw new Error('ABI path may not be null or undefined!');
|
|
172
|
+
if(!accIndex && accIndex !== 0) {
|
|
173
|
+
accIndex = configFile.defaultWallet.index;
|
|
167
174
|
}
|
|
168
175
|
|
|
169
|
-
|
|
176
|
+
wallet = new ethers.Wallet(allAccounts[accIndex].privateKey, currentProvider);
|
|
177
|
+
connectedChain = await currentProvider.getNetwork();
|
|
178
|
+
|
|
179
|
+
const abiPath = abiLoc || localStorage.getItem(`${contractName}_abi`);
|
|
180
|
+
const abi = JSON.parse(fs.readFileSync(abiPath, 'utf8'));
|
|
170
181
|
|
|
171
182
|
const newContract = new ethers.Contract(contractAddr, abi, wallet);
|
|
172
183
|
|
|
184
|
+
// Create contract proxy
|
|
185
|
+
// Wrap the contract instace with proxy
|
|
186
|
+
const proxiedContract = createContractProxy(newContract, currentProvider, allAccounts);
|
|
187
|
+
|
|
188
|
+
// Add to REPL context with proxy
|
|
189
|
+
r.context[contractName] = proxiedContract;
|
|
190
|
+
contracts.set(contractName, proxiedContract);
|
|
191
|
+
|
|
173
192
|
// Update deployer contract list
|
|
174
193
|
const contSpec = {
|
|
175
194
|
address: newContract.target,
|
|
@@ -197,12 +216,6 @@ export async function add(contractName, contractAddr, accIndex, abiLoc, chain) {
|
|
|
197
216
|
newContract.deployType = 'pre-deployed',
|
|
198
217
|
newContract.provider = currentProvider;
|
|
199
218
|
|
|
200
|
-
// Add to contract list
|
|
201
|
-
contracts.set(contractName, newContract);
|
|
202
|
-
|
|
203
|
-
// Add to REPL context
|
|
204
|
-
r.context[contractName] = newContract;
|
|
205
|
-
|
|
206
219
|
// Add result
|
|
207
220
|
const result = {
|
|
208
221
|
index: newContract.index,
|