ethershell 0.1.5-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
@@ -17,7 +17,8 @@ import {
17
17
  compilerOptions,
18
18
  getCompilerOptions,
19
19
  compile,
20
- changeCompPath
20
+ changeCompPath,
21
+ flatten
21
22
  } from '../src/services/build.js';
22
23
  import { set, get, getDefault } from '../src/services/network.js';
23
24
  import { deleteDirectory } from '../src/services/files.js';
@@ -35,7 +36,7 @@ import {
35
36
  changeDefaultAccount
36
37
  } from '../src/services/wallet.js';
37
38
 
38
- import { deploy, add } from '../src/services/addContracts.js';
39
+ import { deploy, add, restore } from '../src/services/addContracts.js';
39
40
  import { getContracts } from '../src/services/contracts.js';
40
41
  import { getConfigInfo, getDefaultAccount } from '../src/services/configSync.js';
41
42
 
@@ -66,6 +67,7 @@ r.context.compInfo = getCompilerOptions;
66
67
  r.context.compOpts = compilerOptions;
67
68
  r.context.compPath = changeCompPath;
68
69
  r.context.build = compile;
70
+ r.context.flatten = flatten;
69
71
 
70
72
  // Config commands
71
73
  r.context.configInfo = getConfigInfo;
@@ -95,3 +97,4 @@ r.context.addContract = add;
95
97
 
96
98
  // Contract
97
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.5-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.contract_index = Array.from(contracts.values()).length;
114
- proxiedContract.contract_name = contractName;
115
- proxiedContract.contract_chain = connectedChain.name;
116
- proxiedContract.contract_chainId = connectedChain.chainId;
117
- proxiedContract.contract_deployType = 'ethershell-deployed';
118
- proxiedContract.contract_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.contract_index = Array.from(contracts.values()).length;
197
- proxiedContract.contract_name = contractName;
198
- proxiedContract.contract_chain = connectedChain.name;
199
- proxiedContract.contract_chainId = connectedChain.chainId;
200
- proxiedContract.contract_deployType = 'ethershell-deployed';
201
- proxiedContract.contract_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
  }
@@ -133,9 +133,6 @@ export function compile(fullPath, selectedContracts, buildPath){
133
133
  [buildPath].forEach(check);
134
134
  }
135
135
 
136
- // Aggregated ABI container: { [contractName]: abiArray }
137
- const aggregatedAbis = {};
138
-
139
136
  let fileExt;
140
137
  if(!fullPath) {
141
138
  fullPath = path.resolve('.', 'contracts');
@@ -144,45 +141,56 @@ export function compile(fullPath, selectedContracts, buildPath){
144
141
  }
145
142
 
146
143
  if(!fileExt){
147
- // Directory: collect .sol files and compile each
148
144
  const solFiles = collectSolFiles(fullPath);
149
145
 
150
146
  if(!solFiles.length){
151
147
  throw 'There is no smart contract in the directory!';
152
148
  } else {
153
- solFiles.forEach((solFile) => {
154
- const contractAbis = build(solFile, selectedContracts, buildPath);
155
- // merge returned ABIs into aggregatedAbis
156
- Object.assign(aggregatedAbis, contractAbis);
157
- })
149
+ for(let i = 0; i < solFiles.length; i++){
150
+ build(solFiles[i], selectedContracts, buildPath);
151
+ }
158
152
  console.log(`Contracts compiled into ${path.resolve(buildPath)}`);
159
153
  }
160
154
  } else {
161
- // Single file
162
- const contractAbis = build(fullPath, selectedContracts, buildPath);
163
- // merge returned ABIs into aggregatedAbis
164
- Object.assign(aggregatedAbis, contractAbis);
155
+ build(fullPath, selectedContracts, buildPath);
165
156
  console.log(`Contract compiled into ${path.resolve(buildPath)}`);
166
157
  }
167
158
 
168
- // Write aggregated ABI file
169
- const abisDir = path.join(buildPath, 'abis');
170
- check(abisDir); // ensure dir exists (same util as builder.js)
171
- const aggregatedAbiPath = path.join(abisDir, 'aggregated.abi.json');
159
+ ////////////////////
160
+ // Generate aggregated ABI after compilation
161
+ const abisDir = path.join(buildPath, 'abis');
162
+ const aggregatedAbiPath = path.join(buildPath, 'aggregated.abi.json');
163
+
164
+ if (fs.existsSync(abisDir)) {
165
+ const files = fs.readdirSync(abisDir).filter(f => f.endsWith('.abi.json'));
166
+
167
+ const aggregated = [];
168
+ for (const file of files) {
169
+ const p = path.join(abisDir, file);
170
+ try {
171
+ const abi = JSON.parse(fs.readFileSync(p, 'utf8'));
172
+ if (Array.isArray(abi)) {
173
+ aggregated.push(...abi);
174
+ } else {
175
+ console.warn(`ABI file ${file} is not an array, skipping from aggregation`);
176
+ }
177
+ } catch (e) {
178
+ console.warn(`Failed to read ABI file ${file} for aggregation: ${e.message}`);
179
+ }
180
+ }
172
181
 
173
- // aggregatedAbis is { ContractName: abiArray }
174
- const flatAbi = Object.values(aggregatedAbis).flat();
182
+ fs.writeFileSync(aggregatedAbiPath, JSON.stringify(aggregated, null, 2));
183
+ console.log('Aggregated ABI generated at', path.resolve(aggregatedAbiPath));
184
+ } else {
185
+ console.warn('No ABI directory found, aggregated ABI not generated.');
186
+ }
175
187
 
176
- // Format: { "ContractName": [ ...abi... ], ... }
177
- fs.writeFileSync(aggregatedAbiPath, JSON.stringify(flatAbi, null, 2));
178
- console.log('Aggregated ABI written to', path.resolve(aggregatedAbiPath));
188
+ ////////////////////
179
189
 
180
190
  // Generate TypeScript types
181
191
  const typesOutputPath = path.join(buildPath, 'types');
182
192
  generateAllTypes(buildPath, typesOutputPath);
183
193
  console.log(`TypeScript types generated in ${path.resolve(typesOutputPath)}`);
184
-
185
- console.log(`Standard JSON Input generated in ${path.resolve(buildPath, 'standard-json')}`);
186
194
  } catch(err){
187
195
  console.error(err);
188
196
  }
@@ -196,4 +204,114 @@ export function changeCompPath(newPath) {
196
204
  compConfig.compilePath = newPath;
197
205
  configFile.compiler.compilePath = compConfig.compilePath;
198
206
  fs.writeFileSync(configPath, JSON.stringify(configFile, null, 2));
199
- }
207
+ }
208
+
209
+ /**
210
+ * Flatten a Solidity contract and its imports into a single file.
211
+ *
212
+ * @param {string} fullPath - Path to the root .sol file.
213
+ * @param {string} [outFile] - Optional path for the flattened output file.
214
+ * Defaults to `<dir>/<name>.flattened.sol`.
215
+ */
216
+ export function flatten(fullPath, outFile) {
217
+ if (!fullPath) {
218
+ throw new Error('flatten(): fullPath to the root Solidity file is required.');
219
+ }
220
+
221
+ const entryPath = path.resolve(fullPath);
222
+ if (!fs.existsSync(entryPath)) {
223
+ throw new Error(`flatten(): entry file does not exist: ${entryPath}`);
224
+ }
225
+
226
+ const visited = new Set();
227
+ const pieces = [];
228
+
229
+ let pragmaLine = null;
230
+ let hasSpdx = false;
231
+
232
+ function processFile(absPath, logicalName) {
233
+ if (visited.has(absPath)) return;
234
+ visited.add(absPath);
235
+
236
+ const raw = fs.readFileSync(absPath, 'utf8');
237
+
238
+ const lines = raw.split(/\r?\n/);
239
+
240
+ // Capture pragma and SPDX once from the entry or first file
241
+ for (const line of lines) {
242
+ const trimmed = line.trim();
243
+ if (!pragmaLine && trimmed.startsWith('pragma solidity')) {
244
+ pragmaLine = trimmed.replace(/[; ]+$/, ';');
245
+ }
246
+ if (!hasSpdx && trimmed.startsWith('// SPDX-License-Identifier:')) {
247
+ hasSpdx = true;
248
+ }
249
+ }
250
+
251
+ const imports = parseImports(raw);
252
+ for (const importPath of imports) {
253
+ const resolved = resolveImportPath(importPath, path.dirname(absPath));
254
+ processFile(resolved, importPath);
255
+ }
256
+
257
+ // Strip SPDX, pragma, and import lines from the body
258
+ const body = lines
259
+ .filter((line) => {
260
+ const trimmed = line.trim();
261
+ if (trimmed.startsWith('// SPDX-License-Identifier:')) return false;
262
+ if (trimmed.startsWith('pragma solidity')) return false;
263
+ if (trimmed.startsWith('import ')) return false;
264
+ return true;
265
+ })
266
+ .join('\n');
267
+
268
+ pieces.push(`\n\n// File: ${logicalName}\n\n${body}\n`);
269
+ }
270
+
271
+ const logicalName = path.basename(entryPath);
272
+ processFile(entryPath, logicalName);
273
+
274
+ let header = '';
275
+ if (hasSpdx) {
276
+ // Multiple different licenses may be mixed; explicit about it
277
+ header += '// SPDX-License-Identifier: MIXED\n';
278
+ }
279
+ if (pragmaLine) {
280
+ header += `${pragmaLine}\n\n`;
281
+ }
282
+
283
+ const flattened = `${header}${pieces.join('')}`;
284
+
285
+ const defaultOut =
286
+ outFile ||
287
+ path.join(
288
+ path.dirname(entryPath),
289
+ `${path.basename(entryPath, '.sol')}.flattened.sol`,
290
+ );
291
+
292
+ fs.writeFileSync(defaultOut, flattened);
293
+ console.log('Flattened contract written to', path.resolve(defaultOut));
294
+ }
295
+
296
+ /*============================= HELPER ==============================*/
297
+ // --- FLATTENING UTILITIES ---
298
+
299
+ function resolveImportPath(importPath, fromDir) {
300
+ if (importPath.startsWith('./') || importPath.startsWith('../')) {
301
+ return path.resolve(fromDir, importPath);
302
+ }
303
+ // Node-style imports from node_modules
304
+ return path.resolve(process.cwd(), 'node_modules', importPath);
305
+ }
306
+
307
+ function parseImports(content) {
308
+ const imports = [];
309
+ const importRegex =
310
+ /import\s+(?:(?:["']([^"']+)["'])|(?:.*?\sfrom\s+["']([^"']+)["']))\s*;/g;
311
+ let match;
312
+ while ((match = importRegex.exec(content))) {
313
+ const importPath = match[1] || match[2];
314
+ if (importPath) imports.push(importPath);
315
+ }
316
+ return imports;
317
+ }
@@ -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);
@@ -81,39 +81,42 @@ export function build(fullPath, selectedContracts, buildPath){
81
81
 
82
82
  // Get the directory containing the contract
83
83
  const contractDir = path.dirname(fullPath);
84
- const filename = path.basename(fullPath, '.sol');
85
- // const source = fs.readFileSync(fullPath, 'utf8');
84
+ const filename = path.basename(fullPath); // keep extension here
85
+ const basename = path.basename(fullPath, '.sol');
86
+
87
+ // Build full standard JSON input, including all imports
88
+ const sources = collectSourcesForStandardJson(fullPath, filename);
86
89
 
87
- // Start collecting from the main contract
88
- let allSources = {}
89
- _collectSources(fullPath, allSources);
90
-
91
90
  const input = {
92
91
  language: 'Solidity',
93
- sources: allSources,
92
+ sources,
94
93
  settings: {
95
94
  outputSelection: {
96
95
  '*': {
97
96
  '*': ['*'],
98
97
  },
99
98
  },
100
- }
99
+ },
101
100
  };
102
101
 
103
102
  // Apply global compiler configuration
104
103
  if (compilerConfig.optimizer) {
105
104
  input.settings.optimizer = {
106
105
  enabled: true,
107
- runs: compilerConfig.optimizerRuns
106
+ runs: compilerConfig.optimizerRuns,
108
107
  };
109
108
  }
109
+
110
110
  if (compilerConfig.viaIR) {
111
111
  input.settings.viaIR = true;
112
112
  }
113
113
 
114
- // Compile without import callback
114
+ // Compile with import callback
115
115
  const output = JSON.parse(
116
- solc.compile(JSON.stringify(input))
116
+ solc.compile(
117
+ JSON.stringify(input),
118
+ { import: (importPath) => findImports(importPath, contractDir) }
119
+ )
117
120
  );
118
121
 
119
122
  if(output.errors) {
@@ -123,13 +126,15 @@ export function build(fullPath, selectedContracts, buildPath){
123
126
  throw errors;
124
127
  }
125
128
  }
126
-
129
+
130
+
131
+
127
132
  // Generate sub-paths of build
128
- const artifacts = path.join(buildPath, 'artifacts');
129
- const abis = path.join(buildPath, 'abis');
130
- const bytecode = path.join(buildPath, 'bytecode');
131
- const metadata = path.join(buildPath, 'metadata');
132
- const standardJsonDir = path.join(buildPath, 'standard-json');
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');
133
138
  const subPaths = [
134
139
  artifacts,
135
140
  abis,
@@ -137,31 +142,17 @@ export function build(fullPath, selectedContracts, buildPath){
137
142
  metadata,
138
143
  standardJsonDir
139
144
  ];
140
- subPaths.forEach(check);
141
-
142
- // Save standard JSON input on standard-json
143
- const jsonInputPath = path.join(standardJsonDir, `${filename}.standard.json`);
144
- fs.writeFileSync(jsonInputPath, JSON.stringify(input, null, 2));
145
-
146
- // Determine the correct key for the main contract in the output
147
- const mainContractPath = path.relative(path.resolve('.'), path.resolve(fullPath)).split(path.sep).join('/');;
148
- const contractsInFile = output.contracts[mainContractPath];
149
-
150
- if (!contractsInFile) {
151
- throw new Error(`Could not find compiled output for ${mainContractPath}`);
152
- }
153
145
 
154
146
  // Ensure all sub-paths exist
155
147
  subPaths.forEach(check);
156
- const allContracts = Object.keys(contractsInFile);
148
+ const allContracts = Object.keys(output.contracts[`${filename}`]);
157
149
  const contractsToSave = selectedContracts.length > 0 ? allContracts.filter(
158
150
  (contractName) => {
159
151
  return selectedContracts.includes(contractName);
160
152
  }
161
153
  ): allContracts;
162
- const resultAbis = {}; // Collect ABIs to return
163
154
  contractsToSave.forEach((contractName) => {
164
- const contractsData = contractsInFile[contractName];
155
+ const contractsData = output.contracts[`${filename}`][contractName];
165
156
  // Save on artifacts
166
157
  const artifactsPath = path.join(artifacts, `${contractName}.json`);
167
158
  fs.writeFileSync(artifactsPath, JSON.stringify(contractsData, null, 2));
@@ -174,19 +165,13 @@ export function build(fullPath, selectedContracts, buildPath){
174
165
  // Save on metadata
175
166
  const metadataPath = path.join(metadata, `${contractName}.metadata.json`);
176
167
  fs.writeFileSync(metadataPath, JSON.stringify(contractsData.metadata, null, 2));
177
-
168
+ // Save standard JSON input for this entry file
169
+ const standardJsonPath = path.join(standardJsonDir,`${basename}.standard-input.json`);
170
+ fs.writeFileSync(standardJsonPath, JSON.stringify(input, null, 2));
178
171
  // Store abis and bytecode on local storage
179
172
  localStorage.setItem(`${contractName}_abi`, abisPath);
180
173
  localStorage.setItem(`${contractName}_bytecode`, bytecodePath);
181
-
182
- // Save ABI
183
- const abi = contractsData.abi || [];
184
- // Collect ABI in memory
185
- resultAbis[contractName] = abi;
186
174
  });
187
-
188
- // Return map of contractName -> abi
189
- return resultAbis;
190
175
  }
191
176
 
192
177
  /**
@@ -205,29 +190,49 @@ export function extractLoadableVersion(fullVersion) {
205
190
  return `v${match[1]}+commit.${match[2]}`;
206
191
  }
207
192
 
208
- /**
209
- * Helper to recursively collect all imports into the sources object
210
- */
211
- function _collectSources(filePath, allSourcesObj) {
212
- const absolutePath = path.resolve(filePath);
213
-
214
- // 1. Force POSIX style (forward slashes) for the map key
215
- let relativePath = path.relative(path.resolve('.'), absolutePath);
216
- relativePath = relativePath.split(path.sep).join('/');
217
-
218
- if (allSourcesObj[relativePath]) return allSourcesObj;
219
-
220
- const content = fs.readFileSync(absolutePath, 'utf8');
221
- allSourcesObj[relativePath] = { content };
222
-
223
- // 2. Resolve imports and recurse
224
- const importRegex = /import\s+(?:\{[^}]*\}\s+from\s+)?['"]([^'"]+)['"]/g;
225
- let match;
226
- while ((match = importRegex.exec(content)) !== null) {
227
- const importPath = match[1];
228
- const resolvedImportPath = path.resolve(path.dirname(absolutePath), importPath);
229
- _collectSources(resolvedImportPath, allSourcesObj);
193
+ /*=========================== HELPER =============================*/
194
+ function resolveImportPath(importPath, fromDir) {
195
+ if (importPath.startsWith('./') || importPath.startsWith('../')) {
196
+ return path.resolve(fromDir, importPath);
197
+ }
198
+
199
+ // Node-style import, resolve from node_modules
200
+ // e.g. '@openzeppelin/contracts/token/ERC20/ERC20.sol'
201
+ return path.resolve(process.cwd(), 'node_modules', importPath);
202
+ }
203
+
204
+ function collectSourcesForStandardJson(entryPath, logicalEntryName) {
205
+ const visited = new Set();
206
+ const sources = {};
207
+
208
+ function processFile(absPath, logicalName) {
209
+ if (visited.has(absPath)) return;
210
+ visited.add(absPath);
211
+
212
+ if (!fs.existsSync(absPath)) {
213
+ console.warn(`Warning: cannot resolve import "${logicalName}" at path "${absPath}"`);
214
+ return;
215
+ }
216
+
217
+ const content = fs.readFileSync(absPath, 'utf8');
218
+ sources[logicalName] = { content };
219
+
220
+ const importRegex =
221
+ /import\s+(?:(?:["']([^"']+)["'])|(?:.*?\sfrom\s+["']([^"']+)["']))\s*;/g;
222
+
223
+ let match;
224
+ while ((match = importRegex.exec(content))) {
225
+ const importPath = match[1] || match[2];
226
+ if (!importPath) continue;
227
+
228
+ 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);
232
+ }
230
233
  }
231
234
 
232
- return allSourcesObj;
235
+ processFile(entryPath, logicalEntryName);
236
+ return sources;
233
237
  }
238
+
@@ -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 = {
25
- index: x.contract_index,
26
- name: x.contract_name,
27
- address: x.target,
28
- chain: x.contract_chain,
29
- chainId: x.contract_chainId,
30
- deployType: x.contract_deployType,
31
- balance: await x.provider.getBalance(x.target)
32
- }
33
- contractsArray.push(contract);
31
+ for (const x of contracts) {
32
+ const balance = await provider.getBalance(x.address);
33
+
34
+ contractsArray.push({
35
+ index: x.index,
36
+ name: x.name,
37
+ address: x.address,
38
+ chain: x.chain,
39
+ chainId: x.chainId,
40
+ deployType: x.deployType,
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
  }
@@ -26,39 +26,12 @@ import { eventOf } from './event.js';
26
26
  export function createContractProxy(contract, provider, allAccounts) {
27
27
  return new Proxy(contract, {
28
28
  get(target, prop) {
29
- // Explicit passthroughs for known non-ABI properties
30
29
  if (prop === 'provider') {
31
30
  return provider;
32
31
  }
33
- if (prop === 'target') {
34
- return target.target;
35
- }
36
- if (prop === 'interface') {
37
- return target.interface;
38
- }
39
- if (prop === 'runner') {
40
- return target.runner;
41
- }
42
- if (prop === 'connect') {
43
- return target.connect.bind(target);
44
- }
45
-
46
- // Allow internal metadata properties to pass through directly
47
- if (typeof prop === 'string' && prop.startsWith('contract_')) {
48
- return target[prop];
49
- }
50
-
51
- // Check if this prop is a contract ABI function
52
- const isContractMethod =
53
- target.interface &&
54
- typeof prop === 'string' &&
55
- (() => {
56
- try { target.interface.getFunction(prop); return true; }
57
- catch { return false; }
58
- })();
59
-
60
- // Pass through non-ABI, non-function properties (e.g. contract_name, contract_index)
61
- if (!isContractMethod && typeof target[prop] !== 'function') {
32
+
33
+ // Pass through non-function properties
34
+ if (typeof target[prop] !== 'function') {
62
35
  return target[prop];
63
36
  }
64
37
 
@@ -100,9 +73,8 @@ export function createContractProxy(contract, provider, allAccounts) {
100
73
 
101
74
  const options = hasOptions ? args.pop() : null;
102
75
 
103
- // Always resolve ABI methods via getFunction to avoid JS built-in property collisions
104
- let contractTarget = target;
105
- let method;
76
+ let method = target[prop];
77
+ let txOptions = {};
106
78
 
107
79
  // Handle 'from' option - switch signer if specified
108
80
  if (options && options.from) {
@@ -124,16 +96,10 @@ export function createContractProxy(contract, provider, allAccounts) {
124
96
 
125
97
  // Create new signer with the specified account
126
98
  const newSigner = new ethers.Wallet(account.privateKey, provider);
127
- contractTarget = target.connect(newSigner);
99
+ const connectedContract = target.connect(newSigner);
100
+ method = connectedContract[prop];
128
101
  }
129
102
 
130
- // Use getFunction for ABI methods to bypass JS name collisions
131
- method = isContractMethod
132
- ? contractTarget.getFunction(prop)
133
- : contractTarget[prop];
134
-
135
- let txOptions = {};
136
-
137
103
  // Build transaction options object with all supported ethers.js v6 options
138
104
  if (options) {
139
105
  // Value (for payable functions)
@@ -194,7 +160,7 @@ export function createContractProxy(contract, provider, allAccounts) {
194
160
  }
195
161
 
196
162
  // Call the method with remaining args and tx options
197
- const result = await method(...args);
163
+ const result = await method.apply(method, args);
198
164
 
199
165
  // Check if result is a transaction response (has wait method)
200
166
  if (result && typeof result.wait === 'function') {
@@ -49,7 +49,7 @@ export function generateAllTypes(buildPath, typesOutputPath = './src/types') {
49
49
  throw new Error(`ABIs directory not found at ${abisPath}`);
50
50
  }
51
51
 
52
- const abiFiles = fs.readdirSync(abisPath).filter(f => f.endsWith('.abi.json') && f !== 'aggregated.abi.json');
52
+ const abiFiles = fs.readdirSync(abisPath).filter(f => f.endsWith('.abi.json'));
53
53
  const generatedFiles = [];
54
54
 
55
55
  abiFiles.forEach(file => {
@@ -1,17 +0,0 @@
1
- Bytecode (what we are looking for)
2
-
3
- 608060405234610370576114d58038038061001981610374565b9283398101906060818303126103705780516001600160401b0381116103705782610045918301610399565b60208201519092906001600160401b03811161037057604091610069918401610399565b91015160ff8116809103610370575f80546001600160a01b0319163317905582516001600160401b03811161028157600254600181811c91168015610366575b602082101461026357601f8111610303575b506020601f82116001146102a057819293945f92610295575b50508160011b915f199060031b1c1916176002555b81516001600160401b03811161028157600354600181811c91168015610277575b602082101461026357601f8111610200575b50602092601f821160011461019f57928192935f92610194575b50508160011b915f199060031b1c1916176003555b60ff1960045416176004557f82488d8ab594db2178e4a45b7106aaa804836e608f001b5d7fcb6c3514730b3e60408051308152336020820152a16040516110ea90816103eb8239f35b015190505f80610136565b601f1982169360035f52805f20915f5b8681106101e857508360019596106101d0575b505050811b0160035561014b565b01515f1960f88460031b161c191690555f80806101c2565b919260206001819286850151815501940192016101af565b60035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f830160051c81019160208410610259575b601f0160051c01905b81811061024e575061011c565b5f8155600101610241565b9091508190610238565b634e487b7160e01b5f52602260045260245ffd5b90607f169061010a565b634e487b7160e01b5f52604160045260245ffd5b015190505f806100d4565b601f1982169060025f52805f20915f5b8181106102eb575095836001959697106102d3575b505050811b016002556100e9565b01515f1960f88460031b161c191690555f80806102c5565b9192602060018192868b0151815501940192016102b0565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c8101916020841061035c575b601f0160051c01905b81811061035157506100bb565b5f8155600101610344565b909150819061033b565b90607f16906100a9565b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761028157604052565b81601f82011215610370578051906001600160401b038211610281576103c8601f8301601f1916602001610374565b928284526020838301011161037057815f9260208093018386015e830101529056fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a714610d765750806306fdde0314610ce4578063095ea7b314610bcd57806316dead1414610b7657806318160ddd14610b5957806323b872dd14610b02578063313ce56714610ae257806340c10f1914610a1c57806342966c68146109635780635353a2d81461074a57806362a09477146106c157806370a08231146106895780638da5cb5b1461066257806395d89b411461059b578063a3895fff1461036e578063a9059cbb14610287578063c112dfa31461021d578063c42069ec14610174578063dd62ed3e146101245763e30c3978146100f8575f80fd5b34610120575f366003190112610120576001546040516001600160a01b039091168152602090f35b5f80fd5b346101205760403660031901126101205761013d610df3565b610145610e09565b6001600160a01b039182165f908152600760209081526040808320949093168252928352819020549051908152f35b346101205760203660031901126101205761018d610df3565b5f546001600160a01b031633810361020757506001600160a01b031680156101f5576020817f7d5f578daab924f3f271d863dd8729e6970e9186812579e22f892146def80f67926bffffffffffffffffffffffff60a01b6001541617600155604051908152a1005b6334d7d10d60e21b5f5260045260245ffd5b63a3ee740f60e01b5f526004523360245260445ffd5b346101205760203660031901126101205760043560ff8116809103610120575f546001600160a01b0316338103610207577fa667a2c7cf0813fa2c1f7a0a0093db4cf6fc7e9c5264f29df1aa880b409a312e6020838060ff196004541617600455604051908152a1005b34610120576040366003190112610120576102a0610df3565b60243590336102bc576313053d9360e21b5f523360045260245ffd5b6001600160a01b031690816102de5750639cfea58360e01b5f5260045260245ffd5b335f908152600660205260409020548181106103555750815f52600660205261030b8160405f2054610ef1565b50335f52600660205260405f20818154039055815f52600660205260405f208181540190556040519081525f5160206110955f395f51905f5260203392a360405160018152602090f35b63db42144d60e01b5f523360045260245260445260645ffd5b346101205761037c36610e41565b5f546001600160a01b03163381036102075750805167ffffffffffffffff8111610587576103ab600354610eb9565b601f811161051f575b50602091601f82116001146104b4579181925f926104a9575b50508160011b915f199060031b1c1916176003555b604051602081525f6003546103f681610eb9565b908160208501526001811690815f14610487575060011461043d575b507fc5109575ebaf6138fc9735faca1c61ff8b7bf4f91870337266cc2bce01a75e15919081900390a1005b60035f9081525f5160206110755f395f51905f52939250905b80821061046c5750909150810160400181610412565b91926001816020925460408588010152019101909291610456565b60ff191660408086019190915291151560051b84019091019150829050610412565b0151905082806103cd565b601f1982169260035f525f5160206110755f395f51905f52915f5b858110610507575083600195106104ef575b505050811b016003556103e2565b01515f1960f88460031b161c191690558280806104e1565b919260206001819286850151815501940192016104cf565b60035f52601f820160051c5f5160206110755f395f51905f52019060208310610572575b601f0160051c5f5160206110755f395f51905f5201905b81811061056757506103b4565b5f815560010161055a565b5f5160206110755f395f51905f529150610543565b634e487b7160e01b5f52604160045260245ffd5b34610120575f366003190112610120576040515f6003546105bb81610eb9565b808452906001811690811561063e57506001146105f3575b6105ef836105e381850382610e1f565b60405191829182610dc9565b0390f35b91905060035f525f5160206110755f395f51905f52915f905b808210610624575090915081016020016105e36105d3565b91926001816020925483858801015201910190929161060c565b60ff191660208086019190915291151560051b840190910191506105e390506105d3565b34610120575f366003190112610120575f546040516001600160a01b039091168152602090f35b34610120576020366003190112610120576001600160a01b036106aa610df3565b165f526006602052602060405f2054604051908152f35b34610120575f366003190112610120576001546001600160a01b03811690338203610733575f80546001600160a01b0319908116841782559091166001556040805192835260208301919091527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c91a1005b5063176f517960e01b5f526004523360245260445ffd5b346101205761075836610e41565b5f546001600160a01b03163381036102075750805167ffffffffffffffff811161058757610787600254610eb9565b601f81116108fb575b50602091601f8211600114610890579181925f92610885575b50508160011b915f199060031b1c1916176002555b604051602081525f6002546107d281610eb9565b908160208501526001811690815f146108635750600114610819575b507f2ae91ea06611bdd535a7ec999b4730beaa64fdbc044a50645c052153e55c3e2d919081900390a1005b60025f9081525f5160206110555f395f51905f52939250905b80821061084857509091508101604001816107ee565b91926001816020925460408588010152019101909291610832565b60ff191660408086019190915291151560051b840190910191508290506107ee565b0151905082806107a9565b601f1982169260025f525f5160206110555f395f51905f52915f5b8581106108e3575083600195106108cb575b505050811b016002556107be565b01515f1960f88460031b161c191690558280806108bd565b919260206001819286850151815501940192016108ab565b60025f52601f820160051c5f5160206110555f395f51905f5201906020831061094e575b601f0160051c5f5160206110555f395f51905f5201905b8181106109435750610790565b5f8155600101610936565b5f5160206110555f395f51905f52915061091f565b34610120576020366003190112610120576004353361098f576313053d9360e21b5f523360045260245ffd5b335f90815260066020526040902054818110610355575f826109b381600554611047565b6005553382526006602052604082206109cd828254611047565b90557f410c5c259085cde81fedf70c1aa308ec839373c26e9b7ada6560a2aca0254eb660406005548151908482526020820152a16040519081525f5160206110955f395f51905f5260203392a3005b3461012057604036600319011261012057610a35610df3565b5f5460243591906001600160a01b031633810361020757506001600160a01b03169081610a6f5750639cfea58360e01b5f5260045260245ffd5b5f5160206110955f395f51905f52602082610a8d5f94600554610ef1565b6005558484526006825260408420610aa6828254610ef1565b90557fcc9c58b575eabd3f6a1ee653e91fcea3ff546867ffc3782a3bbca1f9b6dbb8df604060055481519084825285820152a1604051908152a3005b34610120575f36600319011261012057602060ff60045416604051908152f35b34610120576060366003190112610120576020610b4f610b20610df3565b610b28610e09565b6044359160018060a01b0382165f5260068552610b498360405f2054610ef1565b50610f12565b6040519015158152f35b34610120575f366003190112610120576020600554604051908152f35b3461012057604036600319011261012057610b8f610df3565b610b97610e09565b9060018060a01b03165f52600860205260405f209060018060a01b03165f52602052602060ff60405f2054166040519015158152f35b3461012057604036600319011261012057610be6610df3565b6024359033610c02576322f051b160e21b5f523360045260245ffd5b6001600160a01b0316903382141580610cd0575b80610cc7575b15610cb457335f908152600660205260409020548181106103555750335f52600860205260405f20825f5260205260405f20600160ff19825416179055335f52600760205260405f20825f5260205260405f20610c7a828254610ef1565b90556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a360405160018152602090f35b5063270af7ed60e11b5f5260045260245ffd5b50811515610c1c565b505f546001600160a01b0316821415610c16565b34610120575f366003190112610120576040515f600254610d0481610eb9565b808452906001811690811561063e5750600114610d2b576105ef836105e381850382610e1f565b91905060025f525f5160206110555f395f51905f52915f905b808210610d5c575090915081016020016105e36105d3565b919260018160209254838588010152019101909291610d44565b34610120576020366003190112610120576004359063ffffffff60e01b8216809203610120576020916301ffc9a760e01b8114908115610db8575b5015158152f35b6336372b0760e01b14905083610db1565b602060409281835280519182918282860152018484015e5f828201840152601f01601f1916010190565b600435906001600160a01b038216820361012057565b602435906001600160a01b038216820361012057565b90601f8019910116810190811067ffffffffffffffff82111761058757604052565b60206003198201126101205760043567ffffffffffffffff811161012057816023820112156101205780600401359067ffffffffffffffff82116105875760405192610e97601f8401601f191660200185610e1f565b8284526024838301011161012057815f92602460209301838601378301015290565b90600182811c92168015610ee7575b6020831014610ed357565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610ec8565b91908201809211610efe57565b634e487b7160e01b5f52601160045260245ffd5b6001600160a01b0316908115611034576001600160a01b0316918215611021575f828152600660205260409020548181106103555750338203610f8f575b60205f5160206110955f395f51905f5291835f526006825260405f20818154039055845f526006825260405f20818154019055604051908152a3600190565b5f82815260086020908152604080832033845290915290205460ff161561100e575f828152600760209081526040808320338452909152902054818110610ff557505f828152600760209081526040808320338452909152902080548290039055610f50565b630c95cf2760e11b5f523360045260245260445260645ffd5b6313053d9360e21b5f523360045260245ffd5b82639cfea58360e01b5f5260045260245ffd5b506313053d9360e21b5f5260045260245ffd5b91908203918211610efe5756fe405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5acec2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85bddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212200a75d1a4c912be5dc2d821991e5c0ea3009115e80fb66c939e1f3ac47c98f47964736f6c634300081d0033000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000007506f6c79676f6e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003504f4c0000000000000000000000000000000000000000000000000000000000
4
-
5
-
6
-
7
- - vs what we got -
8
-
9
-
10
-
11
- We tried looking for a match from the list of compiled contract bytecode outputs (as listed below), but was unable to find an exact match.
12
-
13
-
14
-
15
- 1) contracts/ERC20.sol:ERC20
16
-
17
- 608060405234610370576113eb8038038061001981610374565b9283398101906060818303126103705780516001600160401b0381116103705782610045918301610399565b60208201519092906001600160401b03811161037057604091610069918401610399565b91015160ff8116809103610370575f80546001600160a01b0319163317905582516001600160401b03811161028157600254600181811c91168015610366575b602082101461026357601f8111610303575b506020601f82116001146102a057819293945f92610295575b50508160011b915f199060031b1c1916176002555b81516001600160401b03811161028157600354600181811c91168015610277575b602082101461026357601f8111610200575b50602092601f821160011461019f57928192935f92610194575b50508160011b915f199060031b1c1916176003555b60ff1960045416176004557f82488d8ab594db2178e4a45b7106aaa804836e608f001b5d7fcb6c3514730b3e60408051308152336020820152a1604051610fe890816104038239f35b015190505f80610136565b601f1982169360035f52805f20915f5b8681106101e857508360019596106101d0575b505050811b0160035561014b565b01515f1960f88460031b161c191690555f80806101c2565b919260206001819286850151815501940192016101af565b60035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f830160051c81019160208410610259575b601f0160051c01905b81811061024e575061011c565b5f8155600101610241565b9091508190610238565b634e487b7160e01b5f52602260045260245ffd5b90607f169061010a565b634e487b7160e01b5f52604160045260245ffd5b015190505f806100d4565b601f1982169060025f52805f20915f5b8181106102eb575095836001959697106102d3575b505050811b016002556100e9565b01515f1960f88460031b161c191690555f80806102c5565b9192602060018192868b0151815501940192016102b0565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c8101916020841061035c575b601f0160051c01905b81811061035157506100bb565b5f8155600101610344565b909150819061033b565b90607f16906100a9565b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761028157604052565b81601f82011215610370578051906001600160401b038211610281576103c8601f8301601f1916602001610374565b9282845260208383010111610370575f5b8281106103ed57505060205f918301015290565b806020809284010151828287010152016103d956fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a714610b5b5750806306fdde0314610b38578063095ea7b314610a2157806316dead14146109ca57806318160ddd146109ad57806323b872dd14610956578063313ce5671461093657806340c10f191461087057806342966c68146107b75780635353a2d81461063057806362a09477146105a757806370a082311461056f5780638da5cb5b1461054857806395d89b411461050e578063a3895fff1461036e578063a9059cbb14610287578063c112dfa31461021d578063c42069ec14610174578063dd62ed3e146101245763e30c3978146100f8575f80fd5b34610120575f366003190112610120576001546040516001600160a01b039091168152602090f35b5f80fd5b346101205760403660031901126101205761013d610bf5565b610145610c0b565b6001600160a01b039182165f908152600760209081526040808320949093168252928352819020549051908152f35b346101205760203660031901126101205761018d610bf5565b5f546001600160a01b031633810361020757506001600160a01b031680156101f5576020817f7d5f578daab924f3f271d863dd8729e6970e9186812579e22f892146def80f67926bffffffffffffffffffffffff60a01b6001541617600155604051908152a1005b6334d7d10d60e21b5f5260045260245ffd5b63a3ee740f60e01b5f526004523360245260445ffd5b346101205760203660031901126101205760043560ff8116809103610120575f546001600160a01b0316338103610207577fa667a2c7cf0813fa2c1f7a0a0093db4cf6fc7e9c5264f29df1aa880b409a312e6020838060ff196004541617600455604051908152a1005b34610120576040366003190112610120576102a0610bf5565b60243590336102bc576313053d9360e21b5f523360045260245ffd5b6001600160a01b031690816102de5750639cfea58360e01b5f5260045260245ffd5b335f908152600660205260409020548181106103555750815f52600660205261030b8160405f2054610def565b50335f52600660205260405f20818154039055815f52600660205260405f208181540190556040519081525f516020610f935f395f51905f5260203392a360405160018152602090f35b63db42144d60e01b5f523360045260245260445260645ffd5b346101205761037c36610c43565b5f546001600160a01b03163381036102075750805167ffffffffffffffff81116104fa576103ab600354610cbb565b601f8111610492575b50602091601f8211600114610427579181925f9261041c575b50508160011b915f199060031b1c1916176003555b7fc5109575ebaf6138fc9735faca1c61ff8b7bf4f91870337266cc2bce01a75e15604051602081528061041760208201610d7f565b0390a1005b0151905082806103cd565b601f1982169260035f525f516020610f735f395f51905f52915f5b85811061047a57508360019510610462575b505050811b016003556103e2565b01515f1960f88460031b161c19169055828080610454565b91926020600181928685015181550194019201610442565b60035f52601f820160051c5f516020610f735f395f51905f520190602083106104e5575b601f0160051c5f516020610f735f395f51905f5201905b8181106104da57506103b4565b5f81556001016104cd565b5f516020610f735f395f51905f5291506104b6565b634e487b7160e01b5f52604160045260245ffd5b34610120575f366003190112610120576105446040516105388161053181610d7f565b0382610c21565b60405191829182610bae565b0390f35b34610120575f366003190112610120575f546040516001600160a01b039091168152602090f35b34610120576020366003190112610120576001600160a01b03610590610bf5565b165f526006602052602060405f2054604051908152f35b34610120575f366003190112610120576001546001600160a01b03811690338203610619575f80546001600160a01b0319908116841782559091166001556040805192835260208301919091527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c91a1005b5063176f517960e01b5f526004523360245260445ffd5b346101205761063e36610c43565b5f546001600160a01b03163381036102075750805167ffffffffffffffff81116104fa5761066d600254610cbb565b601f811161074f575b50602091601f82116001146106e4579181925f926106d9575b50508160011b915f199060031b1c1916176002555b7f2ae91ea06611bdd535a7ec999b4730beaa64fdbc044a50645c052153e55c3e2d604051602081528061041760208201610cf3565b01519050828061068f565b601f1982169260025f525f516020610f535f395f51905f52915f5b8581106107375750836001951061071f575b505050811b016002556106a4565b01515f1960f88460031b161c19169055828080610711565b919260206001819286850151815501940192016106ff565b60025f52601f820160051c5f516020610f535f395f51905f520190602083106107a2575b601f0160051c5f516020610f535f395f51905f5201905b8181106107975750610676565b5f815560010161078a565b5f516020610f535f395f51905f529150610773565b3461012057602036600319011261012057600435336107e3576313053d9360e21b5f523360045260245ffd5b335f90815260066020526040902054818110610355575f8261080781600554610f45565b600555338252600660205260408220610821828254610f45565b90557f410c5c259085cde81fedf70c1aa308ec839373c26e9b7ada6560a2aca0254eb660406005548151908482526020820152a16040519081525f516020610f935f395f51905f5260203392a3005b3461012057604036600319011261012057610889610bf5565b5f5460243591906001600160a01b031633810361020757506001600160a01b031690816108c35750639cfea58360e01b5f5260045260245ffd5b5f516020610f935f395f51905f526020826108e15f94600554610def565b60055584845260068252604084206108fa828254610def565b90557fcc9c58b575eabd3f6a1ee653e91fcea3ff546867ffc3782a3bbca1f9b6dbb8df604060055481519084825285820152a1604051908152a3005b34610120575f36600319011261012057602060ff60045416604051908152f35b346101205760603660031901126101205760206109a3610974610bf5565b61097c610c0b565b6044359160018060a01b0382165f526006855261099d8360405f2054610def565b50610e10565b6040519015158152f35b34610120575f366003190112610120576020600554604051908152f35b34610120576040366003190112610120576109e3610bf5565b6109eb610c0b565b9060018060a01b03165f52600860205260405f209060018060a01b03165f52602052602060ff60405f2054166040519015158152f35b3461012057604036600319011261012057610a3a610bf5565b6024359033610a56576322f051b160e21b5f523360045260245ffd5b6001600160a01b0316903382141580610b24575b80610b1b575b15610b0857335f908152600660205260409020548181106103555750335f52600860205260405f20825f5260205260405f20600160ff19825416179055335f52600760205260405f20825f5260205260405f20610ace828254610def565b90556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a360405160018152602090f35b5063270af7ed60e11b5f5260045260245ffd5b50811515610a70565b505f546001600160a01b0316821415610a6a565b34610120575f366003190112610120576105446040516105388161053181610cf3565b34610120576020366003190112610120576004359063ffffffff60e01b8216809203610120576020916301ffc9a760e01b8114908115610b9d575b5015158152f35b6336372b0760e01b14905083610b96565b9190916020815282518060208301525f5b818110610bdf575060409293505f838284010152601f8019910116010190565b8060208092870101516040828601015201610bbf565b600435906001600160a01b038216820361012057565b602435906001600160a01b038216820361012057565b90601f8019910116810190811067ffffffffffffffff8211176104fa57604052565b60206003198201126101205760043567ffffffffffffffff811161012057816023820112156101205780600401359067ffffffffffffffff82116104fa5760405192610c99601f8401601f191660200185610c21565b8284526024838301011161012057815f92602460209301838601378301015290565b90600182811c92168015610ce9575b6020831014610cd557565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610cca565b6002545f9291610d0282610cbb565b8082529160018116908115610d635750600114610d1d575050565b60025f9081529293509091905f516020610f535f395f51905f525b838310610d49575060209250010190565b600181602092949394548385870101520191019190610d38565b9050602093945060ff929192191683830152151560051b010190565b6003545f9291610d8e82610cbb565b8082529160018116908115610d635750600114610da9575050565b60035f9081529293509091905f516020610f735f395f51905f525b838310610dd5575060209250010190565b600181602092949394548385870101520191019190610dc4565b91908201809211610dfc57565b634e487b7160e01b5f52601160045260245ffd5b6001600160a01b0316908115610f32576001600160a01b0316918215610f1f575f828152600660205260409020548181106103555750338203610e8d575b60205f516020610f935f395f51905f5291835f526006825260405f20818154039055845f526006825260405f20818154019055604051908152a3600190565b5f82815260086020908152604080832033845290915290205460ff1615610f0c575f828152600760209081526040808320338452909152902054818110610ef357505f828152600760209081526040808320338452909152902080548290039055610e4e565b630c95cf2760e11b5f523360045260245260445260645ffd5b6313053d9360e21b5f523360045260245ffd5b82639cfea58360e01b5f5260045260245ffd5b506313053d9360e21b5f5260045260245ffd5b91908203918211610dfc5756fe405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5acec2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85bddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef{ipfs}64736f6c634300081b0033000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000007506f6c79676f6e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003504f4c0000000000000000000000000000000000000000000000000000000000