ethershell 0.2.3-beta.0 → 0.2.5-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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ethershell",
3
3
  "license": "MIT",
4
- "version": "0.2.3-beta.0",
4
+ "version": "0.2.5-beta.0",
5
5
  "description": "Interactive JavaScript console for Ethereum smart contract management",
6
6
  "author": "Alireza Kiakojouri (alirezaethdev@gmail.com)",
7
7
  "repository": {
@@ -70,7 +70,17 @@ let storedCompConfig;
70
70
  * Object containing properties of config file
71
71
  * @type {Object}
72
72
  */
73
- let configObj;
73
+ let configObj = {
74
+ providerEndpoint: "http://127.0.0.1:8545",
75
+ defaultWallet: {},
76
+ compiler: {
77
+ version: "v0.8.29+commit.ab55807c",
78
+ optimizer: false,
79
+ viaIR: false,
80
+ optimizerRuns: 200,
81
+ compilePath: "./build"
82
+ }
83
+ }
74
84
 
75
85
  // 1) Load config file
76
86
  /**
@@ -101,7 +111,8 @@ if(storedUrl) {
101
111
 
102
112
  // 3) Set Compiler to Memory:
103
113
  // Initialize global configuration of compiler
104
- if(storedCompConfig){
114
+ // if(storedCompConfig){
115
+ if(false){
105
116
  configFile.compiler = storedCompConfig.compiler;
106
117
  console.info(`Compiler is loading ...`);
107
118
  compConfig.currentSolcInstance = await loadSolcVersion(configFile.compiler.version);
@@ -21,12 +21,12 @@ const localStorage = new LocalStorage('./ethershell');
21
21
  /**
22
22
  * Load a specific version of the Solidity compiler
23
23
  * @param {string} version - Solidity compiler version identifier
24
- * @returns {Promise<Object>} Promise resolving to solc instance
24
+ * @returns {Promise} Promise resolving to solc instance
25
25
  * @throws {Error} If version loading fails
26
26
  * @example
27
27
  * loadSolcVersion('v0.8.20+commit.a1b79de6');
28
28
  */
29
- export function loadSolcVersion(version){
29
+ export function loadSolcVersion(version) {
30
30
  return new Promise((resolve, reject) => {
31
31
  solc.loadRemoteVersion(version, (err, solcInstance) => {
32
32
  if (err) reject(err);
@@ -40,12 +40,12 @@ export function loadSolcVersion(version){
40
40
  * @async
41
41
  * @param {string} version - Solidity compiler version identifier
42
42
  * @param {Object} solcInstance - Current solc instance
43
- * @returns {Promise<Object>} New solc instance with the specified version
43
+ * @returns {Promise} New solc instance with the specified version
44
44
  * @throws {Error} If version loading fails
45
45
  * @example
46
46
  * setVersion('v0.8.20+commit.a1b79de6', solcInstance);
47
47
  */
48
- export async function setVersion(version, solcInstance){
48
+ export async function setVersion(version, solcInstance) {
49
49
  solcInstance = await new Promise((resolve, reject) => {
50
50
  solc.loadRemoteVersion(version, (err, solcSpecificVersion) => {
51
51
  if (err) reject(err);
@@ -60,7 +60,7 @@ export async function setVersion(version, solcInstance){
60
60
  /**
61
61
  * Build (compile) a Solidity contract and save artifacts
62
62
  * @param {string} fullPath - Full path to the .sol file
63
- * @param {Array<string>} [selectedContracts=[]] - Array of contract names to compile from the file
63
+ * @param {Array} [selectedContracts=[]] - Array of contract names to compile from the file
64
64
  * @param {string} buildPath - Output directory for compilation artifacts
65
65
  * @returns {void}
66
66
  * @throws {Error} If compilation fails or produces errors
@@ -72,16 +72,16 @@ export async function setVersion(version, solcInstance){
72
72
  * @example
73
73
  * build('./contracts/MyToken.sol', ['MyToken'], './build');
74
74
  */
75
- export function build(fullPath, selectedContracts, buildPath){
76
- if(!selectedContracts){
75
+ export function build(fullPath, selectedContracts, buildPath) {
76
+ if (!selectedContracts) {
77
77
  selectedContracts = [];
78
78
  }
79
79
 
80
80
  const compilerConfig = getCompilerOptions();
81
-
81
+
82
82
  // Get the directory containing the contract
83
83
  const contractDir = path.dirname(fullPath);
84
- const filename = path.basename(fullPath); // keep extension here
84
+ const filename = path.basename(fullPath); // keep extension here
85
85
  const basename = path.basename(fullPath, '.sol');
86
86
 
87
87
  // Build full standard JSON input, including all imports
@@ -119,56 +119,72 @@ export function build(fullPath, selectedContracts, buildPath){
119
119
  )
120
120
  );
121
121
 
122
- if(output.errors) {
122
+ if (output.errors) {
123
123
  // Filter out warnings, only throw on actual errors
124
124
  const errors = output.errors.filter(err => err.severity === 'error');
125
- if(errors.length > 0) {
125
+ if (errors.length > 0) {
126
126
  throw errors;
127
127
  }
128
128
  }
129
129
 
130
-
131
-
132
130
  // Generate sub-paths of build
133
- const artifacts = path.join(buildPath, 'artifacts');
134
- const abis = path.join(buildPath, 'abis');
135
- const bytecode = path.join(buildPath, 'bytecode');
136
- const metadata = path.join(buildPath, 'metadata');
137
- const standardJsonDir = path.join(buildPath, 'standard-json');
131
+ const artifacts = path.join(buildPath, 'artifacts');
132
+ const abis = path.join(buildPath, 'abis');
133
+ const bytecode = path.join(buildPath, 'bytecode');
134
+ const metadata = path.join(buildPath, 'metadata');
135
+ const standardJsonDir = path.join(buildPath, 'standard-json');
138
136
  const subPaths = [
139
- artifacts,
140
- abis,
141
- bytecode,
142
- metadata,
143
- standardJsonDir
137
+ artifacts,
138
+ abis,
139
+ bytecode,
140
+ metadata,
141
+ standardJsonDir,
144
142
  ];
145
143
 
146
144
  // Ensure all sub-paths exist
147
145
  subPaths.forEach(check);
146
+
148
147
  const allContracts = Object.keys(output.contracts[`${filename}`]);
149
- const contractsToSave = selectedContracts.length > 0 ? allContracts.filter(
150
- (contractName) => {
151
- return selectedContracts.includes(contractName);
152
- }
153
- ): allContracts;
148
+ const contractsToSave =
149
+ selectedContracts.length > 0
150
+ ? allContracts.filter((contractName) =>
151
+ selectedContracts.includes(contractName)
152
+ )
153
+ : allContracts;
154
+
154
155
  contractsToSave.forEach((contractName) => {
155
156
  const contractsData = output.contracts[`${filename}`][contractName];
156
- // Save on artifacts
157
+
158
+ // Save artifacts
157
159
  const artifactsPath = path.join(artifacts, `${contractName}.json`);
158
160
  fs.writeFileSync(artifactsPath, JSON.stringify(contractsData, null, 2));
159
- // Save on abis
161
+
162
+ // Save ABI
160
163
  const abisPath = path.join(abis, `${contractName}.abi.json`);
161
164
  fs.writeFileSync(abisPath, JSON.stringify(contractsData.abi, null, 2));
162
- // Save on bytecode
165
+
166
+ // Save bytecode
163
167
  const bytecodePath = path.join(bytecode, `${contractName}.bin`);
164
- fs.writeFileSync(bytecodePath, JSON.stringify(contractsData.evm.bytecode, null, 2));
165
- // Save on metadata
168
+ fs.writeFileSync(
169
+ bytecodePath,
170
+ JSON.stringify(contractsData.evm.bytecode, null, 2)
171
+ );
172
+
173
+ // Save metadata
166
174
  const metadataPath = path.join(metadata, `${contractName}.metadata.json`);
167
- fs.writeFileSync(metadataPath, JSON.stringify(contractsData.metadata, null, 2));
175
+ fs.writeFileSync(
176
+ metadataPath,
177
+ JSON.stringify(contractsData.metadata, null, 2)
178
+ );
179
+
168
180
  // Save standard JSON input for this entry file
169
- const standardJsonPath = path.join(standardJsonDir,`${basename}.standard-input.json`);
181
+ const standardJsonPath = path.join(
182
+ standardJsonDir,
183
+ `${basename}.standard-input.json`
184
+ );
170
185
  fs.writeFileSync(standardJsonPath, JSON.stringify(input, null, 2));
171
- // Store abis and bytecode on local storage
186
+
187
+ // Store ABIs and bytecode in local storage
172
188
  localStorage.setItem(`${contractName}_abi`, abisPath);
173
189
  localStorage.setItem(`${contractName}_bytecode`, bytecodePath);
174
190
  });
@@ -179,7 +195,7 @@ const standardJsonDir = path.join(buildPath, 'standard-json');
179
195
  * @param {string} fullVersion - Full version string (e.g., "0.8.20+commit.a1b79de6.Emscripten.clang")
180
196
  * @returns {string} Loadable version format (e.g., "v0.8.20+commit.a1b79de6")
181
197
  * @example
182
- * extractLoadableVersion("0.8.20+commit.a1b79de6.Emscripten.clang"); // Returns: "v0.8.20+commit.a1b79de6"
198
+ * extractLoadableVersion("0.8.20+commit.a1b79de6.Emscripten.clang"); // "v0.8.20+commit.a1b79de6"
183
199
  */
184
200
  export function extractLoadableVersion(fullVersion) {
185
201
  // Match version number and commit hash from full version string
@@ -191,6 +207,7 @@ export function extractLoadableVersion(fullVersion) {
191
207
  }
192
208
 
193
209
  /*=========================== HELPER =============================*/
210
+
194
211
  function resolveImportPath(importPath, fromDir) {
195
212
  if (importPath.startsWith('./') || importPath.startsWith('../')) {
196
213
  return path.resolve(fromDir, importPath);
@@ -201,21 +218,36 @@ function resolveImportPath(importPath, fromDir) {
201
218
  return path.resolve(process.cwd(), 'node_modules', importPath);
202
219
  }
203
220
 
221
+ /**
222
+ * Collect all Solidity sources reachable from an entry file and build
223
+ * a Standard JSON "sources" object with canonical logical names that
224
+ * match solc's internal resolution.
225
+ *
226
+ * @param {string} entryPath - Absolute path to the entry .sol file
227
+ * @param {string} logicalEntryName - Initial logical name (e.g. 'Cliff.sol')
228
+ * @returns {Object} Standard JSON "sources" map
229
+ */
204
230
  function collectSourcesForStandardJson(entryPath, logicalEntryName) {
205
231
  const visited = new Set();
206
232
  const sources = {};
207
233
 
208
- function processFile(absPath, logicalName) {
234
+ /**
235
+ * @param {string} absPath - Absolute filesystem path
236
+ * @param {string} canonicalName - Logical name used as key in `sources`
237
+ */
238
+ function processFile(absPath, canonicalName) {
209
239
  if (visited.has(absPath)) return;
210
240
  visited.add(absPath);
211
241
 
212
242
  if (!fs.existsSync(absPath)) {
213
- console.warn(`Warning: cannot resolve import "${logicalName}" at path "${absPath}"`);
243
+ console.warn(
244
+ `Warning: cannot resolve import "${canonicalName}" at path "${absPath}"`
245
+ );
214
246
  return;
215
247
  }
216
248
 
217
249
  const content = fs.readFileSync(absPath, 'utf8');
218
- sources[logicalName] = { content };
250
+ sources[canonicalName] = { content };
219
251
 
220
252
  const importRegex =
221
253
  /import\s+(?:(?:["']([^"']+)["'])|(?:.*?\sfrom\s+["']([^"']+)["']))\s*;/g;
@@ -226,13 +258,22 @@ function collectSourcesForStandardJson(entryPath, logicalEntryName) {
226
258
  if (!importPath) continue;
227
259
 
228
260
  const resolved = resolveImportPath(importPath, path.dirname(absPath));
229
- // Use the import string itself as the logical source key,
230
- // which is what solc/Etherscan expect
231
- processFile(resolved, importPath);
261
+
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
+ );
271
+
272
+ processFile(resolved, childCanonicalName);
232
273
  }
233
274
  }
234
275
 
235
- processFile(entryPath, logicalEntryName);
276
+ const entryCanonicalName = logicalEntryName || path.basename(entryPath);
277
+ processFile(entryPath, entryCanonicalName);
236
278
  return sources;
237
- }
238
-
279
+ }