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 +1 -1
- package/src/services/configSync.js +13 -2
- package/src/utils/builder.js +87 -46
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ethershell",
|
|
3
3
|
"license": "MIT",
|
|
4
|
-
"version": "0.2.
|
|
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);
|
package/src/utils/builder.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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);
|
|
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
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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 =
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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
|
-
|
|
157
|
+
|
|
158
|
+
// Save artifacts
|
|
157
159
|
const artifactsPath = path.join(artifacts, `${contractName}.json`);
|
|
158
160
|
fs.writeFileSync(artifactsPath, JSON.stringify(contractsData, null, 2));
|
|
159
|
-
|
|
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
|
-
|
|
165
|
+
|
|
166
|
+
// Save bytecode
|
|
163
167
|
const bytecodePath = path.join(bytecode, `${contractName}.bin`);
|
|
164
|
-
fs.writeFileSync(
|
|
165
|
-
|
|
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(
|
|
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(
|
|
181
|
+
const standardJsonPath = path.join(
|
|
182
|
+
standardJsonDir,
|
|
183
|
+
`${basename}.standard-input.json`
|
|
184
|
+
);
|
|
170
185
|
fs.writeFileSync(standardJsonPath, JSON.stringify(input, null, 2));
|
|
171
|
-
|
|
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"); //
|
|
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
|
-
|
|
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(
|
|
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[
|
|
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
|
-
|
|
230
|
-
//
|
|
231
|
-
|
|
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
|
-
|
|
276
|
+
const entryCanonicalName = logicalEntryName || path.basename(entryPath);
|
|
277
|
+
processFile(entryPath, entryCanonicalName);
|
|
236
278
|
return sources;
|
|
237
|
-
}
|
|
238
|
-
|
|
279
|
+
}
|