ethershell 0.1.6-beta.0 → 0.2.0-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/bin/cli.js CHANGED
@@ -36,7 +36,7 @@ import {
36
36
  changeDefaultAccount
37
37
  } from '../src/services/wallet.js';
38
38
 
39
- import { deploy, add } from '../src/services/addContracts.js';
39
+ import { deploy, add, restore } from '../src/services/addContracts.js';
40
40
  import { getContracts } from '../src/services/contracts.js';
41
41
  import { getConfigInfo, getDefaultAccount } from '../src/services/configSync.js';
42
42
 
@@ -97,3 +97,4 @@ r.context.addContract = add;
97
97
 
98
98
  // Contract
99
99
  r.context.contracts = getContracts;
100
+ r.context.restoreContract = restore;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ethershell",
3
3
  "license": "MIT",
4
- "version": "0.1.6-beta.0",
4
+ "version": "0.2.0-beta.0",
5
5
  "description": "Interactive JavaScript console for Ethereum smart contract management",
6
6
  "author": "Alireza Kiakojouri (alirezaethdev@gmail.com)",
7
7
  "repository": {
@@ -17,6 +17,10 @@ import { LocalStorage } from 'node-localstorage';
17
17
  import { r } from '../../bin/cli.js';
18
18
  import { createContractProxy } from '../utils/contractProxy.js';
19
19
  import { eventOf } from '../utils/event.js';
20
+ import {
21
+ updateContractJSON,
22
+ getContractJSON
23
+ } from '../utils/contractLister.js';
20
24
 
21
25
  /**
22
26
  * Local storage instance for persisting contract metadata
@@ -28,7 +32,29 @@ const localStorage = new LocalStorage('./ethershell');
28
32
  * Map of all deployed and added contracts
29
33
  * @type {Map<string, ethers.Contract>}
30
34
  */
31
- export const contracts = new Map();
35
+ export const contracts = getContractJSON();
36
+
37
+ /**
38
+ * Instantiate stored contracts to interact with the shell
39
+ */
40
+ export async function restore() {
41
+ if(contracts) {
42
+ console.info(`Stored contracts instantiating ...`);
43
+ const contractsLength = contracts.length;
44
+ for(let i = 0; i < contractsLength; i++) {
45
+ await _add(
46
+ contracts[i].name,
47
+ contracts[i].address,
48
+ configFile.defaultWallet.index,
49
+ contracts[i].abiPath
50
+ );
51
+ }
52
+ console.info(`All stored contracts instantiated!`);
53
+ } else {
54
+ return `The storage is empty!`;
55
+ }
56
+ }
57
+
32
58
 
33
59
  /**
34
60
  * Deploy a new smart contract to the blockchain
@@ -92,13 +118,13 @@ export async function deploy(contractName, args, accIndex, chain, abiLoc, byteco
92
118
 
93
119
  allAccounts[accIndex].contracts.push(contSpec);
94
120
 
95
- // Extend contract object
96
- deployTx.index = Array.from(contracts.values()).length;
97
- deployTx.name = contractName;
98
- deployTx.chain = connectedChain.name;
99
- deployTx.chainId = connectedChain.chainId;
100
- deployTx.deployType = 'ethershell-deployed',
101
- deployTx.provider = currentProvider;
121
+ // Decorate contract instance with metadata
122
+ deployTx._contractIndex = contracts.length;
123
+ deployTx._contractName = contractName;
124
+ deployTx._contractChain = connectedChain.name;
125
+ deployTx._contractChainId = connectedChain.chainId;
126
+ deployTx._contractDeployType = 'ethershell-deployed',
127
+ deployTx._contractProvider = currentProvider;
102
128
 
103
129
  //////////////////////////////////
104
130
 
@@ -110,16 +136,31 @@ export async function deploy(contractName, args, accIndex, chain, abiLoc, byteco
110
136
  // Wrap the contract instace with proxy
111
137
  const proxiedContract = createContractProxy(contractInstance, currentProvider, allAccounts);
112
138
 
113
- proxiedContract.index = Array.from(contracts.values()).length;
114
- proxiedContract.name = contractName;
115
- proxiedContract.chain = connectedChain.name;
116
- proxiedContract.chainId = connectedChain.chainId;
117
- proxiedContract.deployType = 'ethershell-deployed';
118
- proxiedContract.provider = currentProvider;
139
+ proxiedContract._contractIndex = contracts.length;
140
+ proxiedContract._contractName = contractName;
141
+ proxiedContract._contractChain = connectedChain.name;
142
+ proxiedContract._contractChainId = connectedChain.chainId;
143
+ proxiedContract._contractDeployType = 'ethershell-deployed';
144
+ proxiedContract._contractProvider = currentProvider;
145
+ proxiedContract._contractABIPath = abiPath;
119
146
 
120
147
  // Add to REPL context with proxy
121
148
  r.context[contractName] = proxiedContract;
122
- contracts.set(contractName, proxiedContract);
149
+
150
+ const contracToStore = {
151
+ index: proxiedContract._contractIndex,
152
+ name: proxiedContract._contractName,
153
+ address: proxiedContract.target,
154
+ chain: proxiedContract._contractChain,
155
+ chainId: proxiedContract._contractChainId,
156
+ deployType: proxiedContract._contractDeployType,
157
+ balance: await proxiedContract.provider.getBalance(proxiedContract.target),
158
+ abiPath: proxiedContract._contractABIPath
159
+ }
160
+ contracts.push(contracToStore);
161
+
162
+ // Update contracts.json
163
+ updateContractJSON(contracts);
123
164
 
124
165
  ////////////////////////////////////////////
125
166
 
@@ -131,12 +172,12 @@ export async function deploy(contractName, args, accIndex, chain, abiLoc, byteco
131
172
  const tx1 = await provider.getTransactionReceipt(deployHash);
132
173
  const eventValues = eventOf(contractInstance, tx1);
133
174
 
134
- // Extend transaction object
135
- tx.ethershellIndex = deployTx.index;
175
+ // Decorate transaction object with metadata
176
+ tx.ethershellIndex = deployTx._contractIndex;
136
177
  tx.address = deployTx.target;
137
- tx.name = deployTx.name;
138
- tx.chain = deployTx.chain;
139
- tx.deployType = deployTx.deployType;
178
+ tx.name = deployTx._contractName;
179
+ tx.chain = deployTx._contractChain;
180
+ tx.deployType = deployTx._contractDeployType;
140
181
 
141
182
  if(eventValues) {
142
183
  tx.eventValues = eventValues;
@@ -163,77 +204,112 @@ export async function deploy(contractName, args, accIndex, chain, abiLoc, byteco
163
204
  */
164
205
  export async function add(contractName, contractAddr, accIndex, abiLoc, chain) {
165
206
  try {
166
- let currentProvider;
167
- let connectedChain;
168
- let wallet;
169
-
170
- if(!contractAddr) {
171
- throw new Error('Contract address may not be null or undefined!');
172
- }
173
-
174
- if(chain) {
175
- currentProvider = new ethers.JsonRpcProvider(chain);
176
- } else {
177
- currentProvider = provider;
178
- }
179
-
180
- if(!accIndex && accIndex !== 0) {
181
- accIndex = configFile.defaultWallet.index;
207
+ const result = await _add(contractName, contractAddr, accIndex, abiLoc, chain);
208
+
209
+ // Decorate contract object
210
+ const contracToStore = {
211
+ index: result.index,
212
+ name: result.name,
213
+ address: result.address,
214
+ chain: result.chain,
215
+ chainId: result.chainId,
216
+ deployType: result.deployType,
217
+ balance: await result.provider.getBalance(result.address),
218
+ abiPath: abiLoc
182
219
  }
220
+ // Update contracts array
221
+ contracts.push(contracToStore);
183
222
 
184
- wallet = new ethers.Wallet(allAccounts[accIndex].privateKey, currentProvider);
185
- connectedChain = await currentProvider.getNetwork();
223
+ // Update contracts.json
224
+ updateContractJSON(contracts);
186
225
 
187
- const abiPath = abiLoc || localStorage.getItem(`${contractName}_abi`);
188
- const abi = JSON.parse(fs.readFileSync(abiPath, 'utf8'));
189
-
190
- const newContract = new ethers.Contract(contractAddr, abi, wallet);
191
-
192
- // Create contract proxy
193
- // Wrap the contract instace with proxy
194
- const proxiedContract = createContractProxy(newContract, currentProvider, allAccounts);
226
+ return result;
227
+ } catch(err) {
228
+ console.error(err);
229
+ }
230
+ }
195
231
 
196
- proxiedContract.index = Array.from(contracts.values()).length;
197
- proxiedContract.name = contractName;
198
- proxiedContract.chain = connectedChain.name;
199
- proxiedContract.chainId = connectedChain.chainId;
200
- proxiedContract.deployType = 'ethershell-deployed';
201
- proxiedContract.provider = currentProvider;
232
+ async function _add(contractName, contractAddr, accIndex, abiLoc, chain) {
233
+ let currentProvider;
234
+ let connectedChain;
235
+ let wallet;
202
236
 
203
- // Add to REPL context with proxy
204
- r.context[contractName] = proxiedContract;
205
- contracts.set(contractName, proxiedContract);
237
+ if(!contractAddr) {
238
+ throw new Error('Contract address may not be null or undefined!');
239
+ }
206
240
 
207
- // Update deployer contract list
208
- const contSpec = {
209
- address: newContract.target,
210
- deployedOn: connectedChain.name,
211
- chainId: connectedChain.chainId
212
- }
241
+ if(chain) {
242
+ currentProvider = new ethers.JsonRpcProvider(chain);
243
+ } else {
244
+ currentProvider = provider;
245
+ }
213
246
 
214
- allAccounts[accIndex].contracts.push(contSpec);
247
+ if(!accIndex && accIndex !== 0) {
248
+ accIndex = configFile.defaultWallet.index;
249
+ }
215
250
 
216
- // Extend contract object
217
- newContract.index = Array.from(contracts.values()).length;
218
- newContract.name = contractName;
219
- newContract.chain = connectedChain.name;
220
- newContract.chainId = connectedChain.chainId;
221
- newContract.deployType = 'pre-deployed',
222
- newContract.provider = currentProvider;
223
-
224
- // Add result
225
- const result = {
226
- index: newContract.index,
227
- name: newContract.name,
228
- address: newContract.target,
229
- chain: newContract.chain,
230
- chainId: newContract.chainId,
231
- deployType: newContract.deployType,
232
- provider: newContract.provider
233
- }
251
+ wallet = new ethers.Wallet(allAccounts[accIndex].privateKey, currentProvider);
252
+ connectedChain = await currentProvider.getNetwork();
253
+
254
+ const abiPath = abiLoc || localStorage.getItem(`${contractName}_abi`);
255
+ const abi = JSON.parse(fs.readFileSync(abiPath, 'utf8'));
256
+
257
+ const newContract = new ethers.Contract(contractAddr, abi, wallet);
258
+
259
+ // Create contract proxy
260
+ // Wrap the contract instace with proxy
261
+ const proxiedContract = createContractProxy(newContract, currentProvider, allAccounts);
262
+
263
+ proxiedContract._contractIndex = contracts.length;
264
+ proxiedContract._contractName = contractName;
265
+ proxiedContract._contractChain = connectedChain.name;
266
+ proxiedContract._contractChainId = connectedChain.chainId;
267
+ proxiedContract._contractDeployType = 'ethershell-deployed';
268
+ proxiedContract._contractProvider = currentProvider;
269
+ proxiedContract._contractABIPath = abiPath;
270
+
271
+ // Add to REPL context with proxy
272
+ r.context[contractName] = proxiedContract;
273
+
274
+ // const contracToStore = {
275
+ // index: proxiedContract._contractIndex,
276
+ // name: proxiedContract._contractName,
277
+ // address: proxiedContract.target,
278
+ // chain: proxiedContract._contractChain,
279
+ // chainId: proxiedContract._contractChainId,
280
+ // deployType: proxiedContract._contractDeployType,
281
+ // balance: await proxiedContract.provider.getBalance(proxiedContract.target),
282
+ // abiPath: proxiedContract._contractABIPath
283
+ // }
284
+ // contracts.push(contracToStore);
285
+
286
+ // Update deployer contract list
287
+ const contSpec = {
288
+ address: newContract.target,
289
+ deployedOn: connectedChain.name,
290
+ chainId: connectedChain.chainId
291
+ }
234
292
 
235
- return result;
236
- } catch(err) {
237
- console.error(err);
293
+ allAccounts[accIndex].contracts.push(contSpec);
294
+
295
+ // Decorate contract instance with metadata
296
+ newContract._contractIndex = contracts.length + 1;
297
+ newContract._contractName = contractName;
298
+ newContract._contractChain = connectedChain.name;
299
+ newContract._contractChainId = connectedChain.chainId;
300
+ newContract._contractDeployType = 'pre-deployed',
301
+ newContract._contractProvider = currentProvider;
302
+
303
+ // Add result
304
+ const result = {
305
+ index: newContract._contractIndex,
306
+ name: newContract._contractName,
307
+ address: newContract.target,
308
+ chain: newContract._contractChain,
309
+ chainId: newContract._contractChainId,
310
+ deployType: newContract._contractDeployType,
311
+ provider: newContract._contractProvider
238
312
  }
313
+
314
+ return result;
239
315
  }
@@ -1,11 +1,12 @@
1
1
  import {
2
2
  loadSolcVersion,
3
- extractLoadableVersion
3
+ extractLoadableVersion
4
4
  } from '../utils/builder.js';
5
5
  import { allAccounts } from './wallet.js';
6
6
  import { serializeBigInts } from '../utils/serialize.js';
7
7
  import fs from 'fs';
8
8
  import { ethers } from 'ethers';
9
+ import solc from 'solc';
9
10
 
10
11
  // Sync Config Memory with Storage Config:
11
12
  /**
@@ -98,7 +99,8 @@ if(storedUrl) {
98
99
 
99
100
  // 3) Set Compiler to Memory:
100
101
  // Initialize global configuration of compiler
101
- if(storedCompConfig){
102
+ // if(storedCompConfig){
103
+ if(false){
102
104
  configFile.compiler = storedCompConfig.compiler;
103
105
  console.info(`Compiler is loading ...`);
104
106
  compConfig.currentSolcInstance = await loadSolcVersion(configFile.compiler.version);
@@ -6,6 +6,14 @@
6
6
  */
7
7
 
8
8
  import { contracts } from '../services/addContracts.js';
9
+ import fs from 'fs';
10
+ import { serializeBigInts } from './serialize.js'
11
+ import { provider } from '../services/configSync.js';
12
+
13
+ /**
14
+ *
15
+ */
16
+ const contractJSONPath = './ethershell/contracts.json';
9
17
 
10
18
  /**
11
19
  * Get array of all contracts with their information
@@ -20,18 +28,54 @@ import { contracts } from '../services/addContracts.js';
20
28
  export async function getContArr() {
21
29
  let contractsArray = [];
22
30
 
23
- for (const x of contracts.values()) {
24
- let contract = {
31
+ for (const x of contracts) {
32
+ const balance = await provider.getBalance(x.address);
33
+
34
+ contractsArray.push({
25
35
  index: x.index,
26
36
  name: x.name,
27
- address: x.target,
37
+ address: x.address,
28
38
  chain: x.chain,
29
39
  chainId: x.chainId,
30
40
  deployType: x.deployType,
31
- balance: await x.provider.getBalance(x.target)
32
- }
33
- contractsArray.push(contract);
41
+ balance,
42
+ abiPath: x.abiPath
43
+ });
34
44
  }
35
45
 
36
46
  return contractsArray;
47
+ }
48
+
49
+ /**
50
+ * Writes/Updates contracts json file
51
+ * @param {Array<string>} contractArr - Contract array
52
+ * @example
53
+ * updateContractJSON([{
54
+ ...
55
+ }]);
56
+ */
57
+ export function updateContractJSON(contractArr) {
58
+ const contractObj = serializeBigInts(contractArr);
59
+ fs.writeFileSync(contractJSONPath, JSON.stringify(contractObj, null, 2));
60
+ }
61
+
62
+ /**
63
+ * Returns pre-added/deployed contracts' objects from saved json file
64
+ * @returns {Object}
65
+ */
66
+ export function getContractJSON(){
67
+ if(fs.existsSync(contractJSONPath)){
68
+ const contractJSON = fs.readFileSync(contractJSONPath, 'utf8');
69
+ // Return empty array if contratcs.json is empty
70
+ if(contractJSON.length === 0) {
71
+ return [];
72
+ } else {
73
+ return JSON.parse(fs.readFileSync(contractJSONPath));
74
+ }
75
+ } else {
76
+ // Generate empty contracts.json if it doesn't exist
77
+ const fd = fs.openSync(contractJSONPath, 'w');
78
+ fs.closeSync(fd);
79
+ return [];
80
+ }
37
81
  }