ethershell 0.1.5-beta.0 → 0.1.6-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 +3 -1
- package/package.json +1 -1
- package/src/services/addContracts.js +12 -12
- package/src/services/build.js +143 -25
- package/src/utils/builder.js +70 -65
- package/src/utils/contractLister.js +5 -5
- package/src/utils/contractProxy.js +8 -42
- package/src/utils/typeGenerator.js +1 -1
- package/src/utils/etherscan.txt +0 -17
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';
|
|
@@ -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;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ethershell",
|
|
3
3
|
"license": "MIT",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.6-beta.0",
|
|
5
5
|
"description": "Interactive JavaScript console for Ethereum smart contract management",
|
|
6
6
|
"author": "Alireza Kiakojouri (alirezaethdev@gmail.com)",
|
|
7
7
|
"repository": {
|
|
@@ -110,12 +110,12 @@ export async function deploy(contractName, args, accIndex, chain, abiLoc, byteco
|
|
|
110
110
|
// Wrap the contract instace with proxy
|
|
111
111
|
const proxiedContract = createContractProxy(contractInstance, currentProvider, allAccounts);
|
|
112
112
|
|
|
113
|
-
proxiedContract.
|
|
114
|
-
proxiedContract.
|
|
115
|
-
proxiedContract.
|
|
116
|
-
proxiedContract.
|
|
117
|
-
proxiedContract.
|
|
118
|
-
proxiedContract.
|
|
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;
|
|
119
119
|
|
|
120
120
|
// Add to REPL context with proxy
|
|
121
121
|
r.context[contractName] = proxiedContract;
|
|
@@ -193,12 +193,12 @@ export async function add(contractName, contractAddr, accIndex, abiLoc, chain) {
|
|
|
193
193
|
// Wrap the contract instace with proxy
|
|
194
194
|
const proxiedContract = createContractProxy(newContract, currentProvider, allAccounts);
|
|
195
195
|
|
|
196
|
-
proxiedContract.
|
|
197
|
-
proxiedContract.
|
|
198
|
-
proxiedContract.
|
|
199
|
-
proxiedContract.
|
|
200
|
-
proxiedContract.
|
|
201
|
-
proxiedContract.
|
|
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;
|
|
202
202
|
|
|
203
203
|
// Add to REPL context with proxy
|
|
204
204
|
r.context[contractName] = proxiedContract;
|
package/src/services/build.js
CHANGED
|
@@ -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.
|
|
154
|
-
|
|
155
|
-
|
|
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
|
-
|
|
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
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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
|
-
|
|
174
|
-
|
|
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
|
-
|
|
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
|
+
}
|
package/src/utils/builder.js
CHANGED
|
@@ -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
|
|
85
|
-
|
|
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
|
|
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
|
|
114
|
+
// Compile with import callback
|
|
115
115
|
const output = JSON.parse(
|
|
116
|
-
solc.compile(
|
|
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
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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(
|
|
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 =
|
|
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
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
//
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
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
|
-
|
|
235
|
+
processFile(entryPath, logicalEntryName);
|
|
236
|
+
return sources;
|
|
233
237
|
}
|
|
238
|
+
|
|
@@ -22,12 +22,12 @@ export async function getContArr() {
|
|
|
22
22
|
|
|
23
23
|
for (const x of contracts.values()) {
|
|
24
24
|
let contract = {
|
|
25
|
-
index: x.
|
|
26
|
-
name: x.
|
|
25
|
+
index: x.index,
|
|
26
|
+
name: x.name,
|
|
27
27
|
address: x.target,
|
|
28
|
-
chain: x.
|
|
29
|
-
chainId: x.
|
|
30
|
-
deployType: x.
|
|
28
|
+
chain: x.chain,
|
|
29
|
+
chainId: x.chainId,
|
|
30
|
+
deployType: x.deployType,
|
|
31
31
|
balance: await x.provider.getBalance(x.target)
|
|
32
32
|
}
|
|
33
33
|
contractsArray.push(contract);
|
|
@@ -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
|
-
|
|
34
|
-
|
|
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
|
-
|
|
104
|
-
let
|
|
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
|
-
|
|
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(
|
|
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')
|
|
52
|
+
const abiFiles = fs.readdirSync(abisPath).filter(f => f.endsWith('.abi.json'));
|
|
53
53
|
const generatedFiles = [];
|
|
54
54
|
|
|
55
55
|
abiFiles.forEach(file => {
|
package/src/utils/etherscan.txt
DELETED
|
@@ -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
|