sol2uml 2.5.11 → 2.5.12
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/README.md +35 -35
- package/lib/diffContracts.d.ts +3 -2
- package/lib/diffContracts.js +61 -35
- package/lib/parserFiles.d.ts +3 -0
- package/lib/parserFiles.js +45 -10
- package/lib/sol2uml.js +11 -10
- package/lib/writerFiles.d.ts +1 -1
- package/lib/writerFiles.js +8 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -51,42 +51,41 @@ Generate UML class or storage diagrams from local Solidity code or verified Soli
|
|
|
51
51
|
Can also flatten or compare verified source files on Etherscan-like explorers.
|
|
52
52
|
|
|
53
53
|
Options:
|
|
54
|
-
-sf, --subfolders <value>
|
|
55
|
-
-f, --outputFormat <value>
|
|
56
|
-
-o, --outputFileName <value>
|
|
57
|
-
-i, --ignoreFilesOrFolders <filesOrFolders>
|
|
58
|
-
-n, --network <network>
|
|
59
|
-
|
|
60
|
-
-
|
|
61
|
-
-
|
|
62
|
-
-
|
|
63
|
-
-
|
|
64
|
-
-
|
|
65
|
-
-
|
|
66
|
-
-
|
|
67
|
-
-
|
|
68
|
-
-h, --help display help for command
|
|
54
|
+
-sf, --subfolders <value> number of subfolders that will be recursively searched for Solidity files. (default: all)
|
|
55
|
+
-f, --outputFormat <value> output file format. (choices: "svg", "png", "dot", "all", default: "svg")
|
|
56
|
+
-o, --outputFileName <value> output file name
|
|
57
|
+
-i, --ignoreFilesOrFolders <filesOrFolders> comma-separated list of files or folders to ignore
|
|
58
|
+
-n, --network <network> Ethereum network which maps to a blockchain explorer (choices: "mainnet", "goerli", "sepolia", "polygon", "arbitrum", "avalanche", "bsc", "crono", "fantom", "moonbeam", "optimism", "gnosis", "celo", default: "mainnet", env: ETH_NETWORK)
|
|
59
|
+
-e, --explorerUrl <url> Override the `network` option with a custom blockchain explorer API URL. eg Polygon Mumbai testnet https://api-testnet.polygonscan.com/api (env: EXPLORER_URL)
|
|
60
|
+
-k, --apiKey <key> Blockchain explorer API key. eg Etherscan, Arbiscan, Optimism, BscScan, CronoScan, FTMScan, PolygonScan or SnowTrace API key (env: SCAN_API_KEY)
|
|
61
|
+
-bc, --backColor <color> Canvas background color. "none" will use a transparent canvas. (default: "white")
|
|
62
|
+
-sc, --shapeColor <color> Basic drawing color for graphics, not text (default: "black")
|
|
63
|
+
-fc, --fillColor <color> Color used to fill the background of a node (default: "gray95")
|
|
64
|
+
-tc, --textColor <color> Color used for text (default: "black")
|
|
65
|
+
-v, --verbose run with debugging statements (default: false)
|
|
66
|
+
-V, --version output the version number
|
|
67
|
+
-h, --help display help for command
|
|
69
68
|
|
|
70
69
|
Commands:
|
|
71
|
-
class [options] <fileFolderAddress>
|
|
72
|
-
storage [options] <fileFolderAddress>
|
|
70
|
+
class [options] <fileFolderAddress> Generates a UML class diagram from Solidity source code.
|
|
71
|
+
storage [options] <fileFolderAddress> Visually display a contract's storage slots.
|
|
73
72
|
|
|
74
|
-
|
|
75
|
-
flatten <contractAddress>
|
|
73
|
+
WARNING: sol2uml does not use the Solidity compiler so may differ with solc. A known example is fixed-sized arrays declared with an expression will fail to be sized.
|
|
74
|
+
flatten <contractAddress> Merges verified source files for a contract from a Blockchain explorer into one local Solidity file.
|
|
76
75
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
diff [options] <addressA> <
|
|
76
|
+
In order for the merged code to compile, the following is done:
|
|
77
|
+
1. pragma solidity is set using the compiler of the verified contract.
|
|
78
|
+
2. All pragma solidity lines in the source files are commented out.
|
|
79
|
+
3. File imports are commented out.
|
|
80
|
+
4. "SPDX-License-Identifier" is renamed to "SPDX--License-Identifier".
|
|
81
|
+
5. Contract dependencies are analysed so the files are merged in an order that will compile.
|
|
82
|
+
diff [options] <addressA> <fileFoldersAddress> Compare verified Solidity code to another verified contract, a local file or local source files.
|
|
84
83
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
help [command]
|
|
84
|
+
The results show the comparison of contract A to B.
|
|
85
|
+
The green sections are additions to contract B that are not in contract A.
|
|
86
|
+
The red sections are removals from contract A that are not in contract B.
|
|
87
|
+
The line numbers are from contract B. There are no line numbers for the red sections as they are not in contract B.
|
|
88
|
+
help [command] display help for command
|
|
90
89
|
```
|
|
91
90
|
|
|
92
91
|
### Class usage
|
|
@@ -182,7 +181,7 @@ Options:
|
|
|
182
181
|
```
|
|
183
182
|
Usage: sol2uml diff [options] <addressA> <addressB or comma-separated folders>
|
|
184
183
|
|
|
185
|
-
Compare verified Solidity code to another verified contract or local source files.
|
|
184
|
+
Compare verified Solidity code to another verified contract, a local file or local source files.
|
|
186
185
|
|
|
187
186
|
The results show the comparison of contract A to B.
|
|
188
187
|
The green sections are additions to contract B that are not in contract A.
|
|
@@ -191,9 +190,10 @@ The line numbers are from contract B. There are no line numbers for the red sect
|
|
|
191
190
|
|
|
192
191
|
Arguments:
|
|
193
192
|
addressA Contract address in hexadecimal format with a 0x prefix of the first contract
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
193
|
+
fileFoldersAddress Location of the contract source code to compare against. Can be a filename, comma-separated list of local folders or a contract address. Examples:
|
|
194
|
+
"flat.sol" will compare against a local file called "flat.sol". This must be used when address A's verified source code is a single, flat file.
|
|
195
|
+
".,node_modules" will compare against local files under the current working folder and the node_modules folder. This is used when address A's verified source code is multiple files.
|
|
196
|
+
0x1091588Cc431275F99DC5Df311fd8E1Ab81c89F3 will compare against the verified source code from Etherscan.
|
|
197
197
|
|
|
198
198
|
Options:
|
|
199
199
|
-s, --summary Only show a summary of the file differences (default: false)
|
package/lib/diffContracts.d.ts
CHANGED
|
@@ -20,14 +20,15 @@ interface CompareContracts {
|
|
|
20
20
|
files: DiffFiles[];
|
|
21
21
|
contractNameA: string;
|
|
22
22
|
contractNameB?: string;
|
|
23
|
+
local?: 'file' | 'folders';
|
|
23
24
|
}
|
|
24
25
|
export declare const compareVerifiedContracts: (addressA: string, aEtherscanParser: EtherscanParser, addressB: string, bEtherscanParser: EtherscanParser, options: DiffOptions) => Promise<void>;
|
|
25
|
-
export declare const compareVerified2Local: (addressA: string, aEtherscanParser: EtherscanParser,
|
|
26
|
+
export declare const compareVerified2Local: (addressA: string, aEtherscanParser: EtherscanParser, fileOrBaseFolders: string[], options: DiffOptions) => Promise<void>;
|
|
26
27
|
export declare const compareFlattenContracts: (addressA: string, addressB: string, aEtherscanParser: EtherscanParser, bEtherscanParser: EtherscanParser, options: FlattenAndDiffOptions) => Promise<{
|
|
27
28
|
contractNameA: string;
|
|
28
29
|
contractNameB: string;
|
|
29
30
|
}>;
|
|
30
|
-
export declare const diffVerified2Local: (addressA: string, etherscanParserA: EtherscanParser,
|
|
31
|
+
export declare const diffVerified2Local: (addressA: string, etherscanParserA: EtherscanParser, fileOrBaseFolders: string[], ignoreFilesOrFolders?: string[]) => Promise<CompareContracts>;
|
|
31
32
|
export declare const diffVerifiedContracts: (addressA: string, addressB: string, etherscanParserA: EtherscanParser, etherscanParserB: EtherscanParser, options: DiffOptions) => Promise<CompareContracts>;
|
|
32
33
|
export declare const displayFileDiffSummary: (fileDiffs: DiffFiles[]) => void;
|
|
33
34
|
export declare const displayFileDiffs: (fileDiffs: DiffFiles[], options?: {
|
package/lib/diffContracts.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.displayFileDiffs = exports.displayFileDiffSummary = exports.diffVerifiedContracts = exports.diffVerified2Local = exports.compareFlattenContracts = exports.compareVerified2Local = exports.compareVerifiedContracts = void 0;
|
|
4
4
|
const clc = require('cli-color');
|
|
5
|
-
const fs_1 = require("fs");
|
|
6
5
|
const path_1 = require("path");
|
|
7
6
|
const parserFiles_1 = require("./parserFiles");
|
|
8
7
|
const writerFiles_1 = require("./writerFiles");
|
|
@@ -19,14 +18,19 @@ const compareVerifiedContracts = async (addressA, aEtherscanParser, addressB, bE
|
|
|
19
18
|
(0, exports.displayFileDiffSummary)(files);
|
|
20
19
|
};
|
|
21
20
|
exports.compareVerifiedContracts = compareVerifiedContracts;
|
|
22
|
-
const compareVerified2Local = async (addressA, aEtherscanParser,
|
|
21
|
+
const compareVerified2Local = async (addressA, aEtherscanParser, fileOrBaseFolders, options) => {
|
|
23
22
|
// compare verified contract to local files
|
|
24
|
-
const { contractNameA, files } = await (0, exports.diffVerified2Local)(addressA, aEtherscanParser,
|
|
23
|
+
const { contractNameA, files, local } = await (0, exports.diffVerified2Local)(addressA, aEtherscanParser, fileOrBaseFolders);
|
|
25
24
|
if (!options.summary) {
|
|
26
25
|
(0, exports.displayFileDiffs)(files, options);
|
|
27
26
|
}
|
|
28
27
|
console.log(`Compared the "${contractNameA}" contract with address ${addressA} on ${options.network}`);
|
|
29
|
-
|
|
28
|
+
if (local) {
|
|
29
|
+
console.log(`to local file "${fileOrBaseFolders}"\n`);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
console.log(`to local files under folders "${fileOrBaseFolders}"\n`);
|
|
33
|
+
}
|
|
30
34
|
(0, exports.displayFileDiffSummary)(files);
|
|
31
35
|
};
|
|
32
36
|
exports.compareVerified2Local = compareVerified2Local;
|
|
@@ -36,25 +40,52 @@ const compareFlattenContracts = async (addressA, addressB, aEtherscanParser, bEt
|
|
|
36
40
|
const { solidityCode: codeB, contractName: contractNameB } = await bEtherscanParser.getSolidityCode(addressB, options.bFile || options.aFile);
|
|
37
41
|
(0, diff_1.diffCode)(codeA, codeB, options.lineBuffer);
|
|
38
42
|
if (options.saveFiles) {
|
|
39
|
-
await (0, writerFiles_1.
|
|
40
|
-
await (0, writerFiles_1.
|
|
43
|
+
await (0, writerFiles_1.writeSourceCode)(codeA, addressA);
|
|
44
|
+
await (0, writerFiles_1.writeSourceCode)(codeB, addressB);
|
|
45
|
+
}
|
|
46
|
+
if (options.bFile || options.aFile) {
|
|
47
|
+
console.log(`Compared the "${options.aFile}" file for the "${contractNameA}" contract with address ${addressA} on ${options.network}`);
|
|
48
|
+
console.log(`to the "${options.bFile || options.aFile}" file for the "${contractNameB}" contract with address ${addressB} on ${options.bNetwork || options.network}\n`);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
console.log(`Compared the flattened "${contractNameA}" contract with address ${addressA} on ${options.network}`);
|
|
52
|
+
console.log(`to the flattened "${contractNameB}" contract with address ${addressB} on ${options.bNetwork || options.network}\n`);
|
|
41
53
|
}
|
|
42
|
-
console.log(`Compared the flattened "${contractNameA}" contract with address ${addressA} on ${options.network}`);
|
|
43
|
-
console.log(`to the flattened "${contractNameB}" contract with address ${addressB} on ${options.bNetwork || options.network}\n`);
|
|
44
54
|
return { contractNameA, contractNameB };
|
|
45
55
|
};
|
|
46
56
|
exports.compareFlattenContracts = compareFlattenContracts;
|
|
47
|
-
const diffVerified2Local = async (addressA, etherscanParserA,
|
|
57
|
+
const diffVerified2Local = async (addressA, etherscanParserA, fileOrBaseFolders, ignoreFilesOrFolders = []) => {
|
|
48
58
|
const files = [];
|
|
49
59
|
// Get all the source files for the verified contract from Etherscan
|
|
50
60
|
const { files: aFiles, contractName: contractNameA } = await etherscanParserA.getSourceCode(addressA);
|
|
51
|
-
|
|
61
|
+
if (aFiles.length === 1 && (0, regEx_1.isAddress)(aFiles[0].filename)) {
|
|
62
|
+
// The verified contract is a single, flat file
|
|
63
|
+
const aFile = aFiles[0];
|
|
64
|
+
const bFile = fileOrBaseFolders[0];
|
|
65
|
+
if ((0, parserFiles_1.isFolder)(bFile)) {
|
|
66
|
+
throw Error(`Contract with address ${addressA} is a single, flat file so cannot be compared to a local files under folder(s) "${fileOrBaseFolders.toString()}".`);
|
|
67
|
+
}
|
|
68
|
+
// Try and read the bFile
|
|
69
|
+
const bCode = (0, parserFiles_1.readFile)(bFile, 'sol');
|
|
70
|
+
files.push({
|
|
71
|
+
filename: aFile.filename,
|
|
72
|
+
aCode: aFile.code,
|
|
73
|
+
bCode,
|
|
74
|
+
result: aFile.code === bCode ? 'match' : 'changed',
|
|
75
|
+
});
|
|
76
|
+
return {
|
|
77
|
+
files,
|
|
78
|
+
contractNameA,
|
|
79
|
+
local: 'file',
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const bFiles = await (0, parserFiles_1.getSolidityFilesFromFolderOrFiles)(fileOrBaseFolders, ignoreFilesOrFolders);
|
|
52
83
|
// For each file in the A contract
|
|
53
84
|
for (const aFile of aFiles) {
|
|
54
85
|
// Look for A contract filename in local filesystem
|
|
55
86
|
let bFile;
|
|
56
87
|
// for each of the base folders
|
|
57
|
-
for (const baseFolder of
|
|
88
|
+
for (const baseFolder of fileOrBaseFolders) {
|
|
58
89
|
bFile = bFiles.find((bFile) => {
|
|
59
90
|
const resolvedPath = (0, path_1.resolve)(process.cwd(), baseFolder, aFile.filename);
|
|
60
91
|
return bFile === resolvedPath;
|
|
@@ -64,31 +95,26 @@ const diffVerified2Local = async (addressA, etherscanParserA, baseFolders, ignor
|
|
|
64
95
|
}
|
|
65
96
|
}
|
|
66
97
|
if (bFile) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
else {
|
|
82
|
-
files.push({
|
|
83
|
-
filename: aFile.filename,
|
|
84
|
-
aCode: aFile.code,
|
|
85
|
-
bCode,
|
|
86
|
-
result: 'match',
|
|
87
|
-
});
|
|
88
|
-
}
|
|
98
|
+
debug(`Matched verified file ${aFile.filename} to local file ${bFile}`);
|
|
99
|
+
// Try and read code from bFile
|
|
100
|
+
const bCode = (0, parserFiles_1.readFile)(bFile);
|
|
101
|
+
// The A contract filename exists in the B contract
|
|
102
|
+
if (aFile.code !== bCode) {
|
|
103
|
+
// console.log(`${aFile.filename} ${clc.red('different')}:`)
|
|
104
|
+
files.push({
|
|
105
|
+
filename: aFile.filename,
|
|
106
|
+
aCode: aFile.code,
|
|
107
|
+
bCode,
|
|
108
|
+
result: 'changed',
|
|
109
|
+
});
|
|
89
110
|
}
|
|
90
|
-
|
|
91
|
-
|
|
111
|
+
else {
|
|
112
|
+
files.push({
|
|
113
|
+
filename: aFile.filename,
|
|
114
|
+
aCode: aFile.code,
|
|
115
|
+
bCode,
|
|
116
|
+
result: 'match',
|
|
117
|
+
});
|
|
92
118
|
}
|
|
93
119
|
}
|
|
94
120
|
else {
|
package/lib/parserFiles.d.ts
CHANGED
|
@@ -4,3 +4,6 @@ export declare const parseUmlClassesFromFiles: (filesOrFolders: readonly string[
|
|
|
4
4
|
export declare function getSolidityFilesFromFolderOrFiles(folderOrFilePaths: readonly string[], ignoreFilesOrFolders: readonly string[], subfolders?: number): Promise<string[]>;
|
|
5
5
|
export declare function getSolidityFilesFromFolderOrFile(folderOrFilePath: string, ignoreFilesOrFolders?: readonly string[], depthLimit?: number): Promise<string[]>;
|
|
6
6
|
export declare function parseSolidityFile(fileName: string): ASTNode;
|
|
7
|
+
export declare const readFile: (fileName: string, extension?: string) => string;
|
|
8
|
+
export declare const isFile: (fileName: string) => boolean;
|
|
9
|
+
export declare const isFolder: (fileName: string) => boolean;
|
package/lib/parserFiles.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.parseSolidityFile = exports.getSolidityFilesFromFolderOrFile = exports.getSolidityFilesFromFolderOrFiles = exports.parseUmlClassesFromFiles = void 0;
|
|
6
|
+
exports.isFolder = exports.isFile = exports.readFile = exports.parseSolidityFile = exports.getSolidityFilesFromFolderOrFile = exports.getSolidityFilesFromFolderOrFiles = exports.parseUmlClassesFromFiles = void 0;
|
|
7
7
|
const fs_1 = require("fs");
|
|
8
8
|
const path_1 = require("path");
|
|
9
9
|
const klaw_1 = __importDefault(require("klaw"));
|
|
@@ -89,15 +89,7 @@ function getSolidityFilesFromFolderOrFile(folderOrFilePath, ignoreFilesOrFolders
|
|
|
89
89
|
}
|
|
90
90
|
exports.getSolidityFilesFromFolderOrFile = getSolidityFilesFromFolderOrFile;
|
|
91
91
|
function parseSolidityFile(fileName) {
|
|
92
|
-
|
|
93
|
-
try {
|
|
94
|
-
solidityCode = (0, fs_1.readFileSync)(fileName, 'utf8');
|
|
95
|
-
}
|
|
96
|
-
catch (err) {
|
|
97
|
-
throw new Error(`Failed to read solidity file ${fileName}.`, {
|
|
98
|
-
cause: err,
|
|
99
|
-
});
|
|
100
|
-
}
|
|
92
|
+
const solidityCode = (0, exports.readFile)(fileName);
|
|
101
93
|
try {
|
|
102
94
|
return (0, parser_1.parse)(solidityCode, {});
|
|
103
95
|
}
|
|
@@ -108,4 +100,47 @@ function parseSolidityFile(fileName) {
|
|
|
108
100
|
}
|
|
109
101
|
}
|
|
110
102
|
exports.parseSolidityFile = parseSolidityFile;
|
|
103
|
+
const readFile = (fileName, extension) => {
|
|
104
|
+
try {
|
|
105
|
+
// try to read file with no extension
|
|
106
|
+
return (0, fs_1.readFileSync)(fileName, 'utf8');
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
if (!extension) {
|
|
110
|
+
throw new Error(`Failed to read file "${fileName}".`, {
|
|
111
|
+
cause: err,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
// try to read file with extension
|
|
116
|
+
return (0, fs_1.readFileSync)(`${fileName}.${extension}`, 'utf8');
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
throw new Error(`Failed to read file "${fileName}" or "${fileName}.${extension}".`, {
|
|
120
|
+
cause: err,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
exports.readFile = readFile;
|
|
126
|
+
const isFile = (fileName) => {
|
|
127
|
+
try {
|
|
128
|
+
const file = (0, fs_1.lstatSync)(fileName);
|
|
129
|
+
return file.isFile();
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
exports.isFile = isFile;
|
|
136
|
+
const isFolder = (fileName) => {
|
|
137
|
+
try {
|
|
138
|
+
const file = (0, fs_1.lstatSync)(fileName);
|
|
139
|
+
return file.isDirectory();
|
|
140
|
+
}
|
|
141
|
+
catch (err) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
exports.isFolder = isFolder;
|
|
111
146
|
//# sourceMappingURL=parserFiles.js.map
|
package/lib/sol2uml.js
CHANGED
|
@@ -209,7 +209,7 @@ In order for the merged code to compile, the following is done:
|
|
|
209
209
|
const { solidityCode, contractName } = await etherscanParser.getSolidityCode(contractAddress);
|
|
210
210
|
// Write Solidity to the contract address
|
|
211
211
|
const outputFilename = combinedOptions.outputFileName || contractName;
|
|
212
|
-
await (0, writerFiles_1.
|
|
212
|
+
await (0, writerFiles_1.writeSourceCode)(solidityCode, outputFilename);
|
|
213
213
|
}
|
|
214
214
|
catch (err) {
|
|
215
215
|
console.error(err);
|
|
@@ -219,16 +219,17 @@ In order for the merged code to compile, the following is done:
|
|
|
219
219
|
program
|
|
220
220
|
.command('diff')
|
|
221
221
|
.usage('[options] <addressA> <addressB or comma-separated folders>')
|
|
222
|
-
.description(`Compare verified Solidity code to another verified contract or local source files.
|
|
222
|
+
.description(`Compare verified Solidity code to another verified contract, a local file or local source files.
|
|
223
223
|
|
|
224
224
|
The results show the comparison of contract A to B.
|
|
225
225
|
The ${clc.green('green')} sections are additions to contract B that are not in contract A.
|
|
226
226
|
The ${clc.red('red')} sections are removals from contract A that are not in contract B.
|
|
227
227
|
The line numbers are from contract B. There are no line numbers for the red sections as they are not in contract B.\n`)
|
|
228
228
|
.argument('<addressA>', 'Contract address in hexadecimal format with a 0x prefix of the first contract', validators_1.validateAddress)
|
|
229
|
-
.argument('<
|
|
230
|
-
|
|
231
|
-
|
|
229
|
+
.argument('<fileFoldersAddress>', `Location of the contract source code to compare against. Can be a filename, comma-separated list of local folders or a contract address. Examples:
|
|
230
|
+
"flat.sol" will compare against a local file called "flat.sol". This must be used when address A's verified source code is a single, flat file.
|
|
231
|
+
".,node_modules" will compare against local files under the current working folder and the node_modules folder. This is used when address A's verified source code is multiple files.
|
|
232
|
+
0x1091588Cc431275F99DC5Df311fd8E1Ab81c89F3 will compare against the verified source code from Etherscan.`)
|
|
232
233
|
.option('-s, --summary', 'Only show a summary of the file differences', false)
|
|
233
234
|
.option('-af --aFile <value>', 'Contract A source code filename without the .sol extension (default: compares all source files)')
|
|
234
235
|
.option('-bf --bFile <value>', 'Contract B source code filename without the .sol extension (default: aFile if specified)')
|
|
@@ -238,16 +239,16 @@ or ".,node_modules" will compare against local files in the current folder and t
|
|
|
238
239
|
.option('--flatten', 'Flatten into a single file before comparing. Only works when comparing two verified contracts, not to local files', false)
|
|
239
240
|
.option('--saveFiles', 'Save the flattened contract code to the filesystem when using the `flatten` option. The file names will be the contract address with a .sol extension', false)
|
|
240
241
|
.option('-l, --lineBuffer <value>', 'Minimum number of lines before and after changes (default: 4)', validators_1.validateLineBuffer)
|
|
241
|
-
.action(async (addressA,
|
|
242
|
+
.action(async (addressA, fileFoldersAddress, options, command) => {
|
|
242
243
|
try {
|
|
243
|
-
debug(`About to compare ${addressA} to ${
|
|
244
|
+
debug(`About to compare ${addressA} to ${fileFoldersAddress}`);
|
|
244
245
|
const combinedOptions = {
|
|
245
246
|
...command.parent._optionValues,
|
|
246
247
|
...options,
|
|
247
248
|
};
|
|
248
249
|
const aEtherscanParser = new parserEtherscan_1.EtherscanParser(combinedOptions.apiKey, combinedOptions.network, combinedOptions.explorerUrl);
|
|
249
|
-
if ((0, regEx_1.isAddress)(
|
|
250
|
-
const addressB =
|
|
250
|
+
if ((0, regEx_1.isAddress)(fileFoldersAddress)) {
|
|
251
|
+
const addressB = fileFoldersAddress;
|
|
251
252
|
const bEtherscanParser = new parserEtherscan_1.EtherscanParser(combinedOptions.bApiKey || combinedOptions.apiKey, combinedOptions.bNetwork || combinedOptions.network, combinedOptions.bExplorerUrl || combinedOptions.explorerUrl);
|
|
252
253
|
// If flattening or just comparing a single file
|
|
253
254
|
if (options.flatten || options.aFile) {
|
|
@@ -258,7 +259,7 @@ or ".,node_modules" will compare against local files in the current folder and t
|
|
|
258
259
|
}
|
|
259
260
|
}
|
|
260
261
|
else {
|
|
261
|
-
const localFolders =
|
|
262
|
+
const localFolders = fileFoldersAddress.split(',');
|
|
262
263
|
await (0, diffContracts_1.compareVerified2Local)(addressA, aEtherscanParser, localFolders, combinedOptions);
|
|
263
264
|
}
|
|
264
265
|
}
|
package/lib/writerFiles.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export type OutputFormats = 'svg' | 'png' | 'dot' | 'all';
|
|
|
8
8
|
*/
|
|
9
9
|
export declare const writeOutputFiles: (dot: string, contractName: string, outputFormat?: OutputFormats, outputFilename?: string) => Promise<void>;
|
|
10
10
|
export declare function convertDot2Svg(dot: string): any;
|
|
11
|
-
export declare function
|
|
11
|
+
export declare function writeSourceCode(code: string, filename?: string, extension?: string): void;
|
|
12
12
|
export declare function writeDot(dot: string, filename: string): void;
|
|
13
13
|
/**
|
|
14
14
|
* Writes an SVG file to the file system.
|
package/lib/writerFiles.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.writePng = exports.writeSVG = exports.writeDot = exports.
|
|
6
|
+
exports.writePng = exports.writeSVG = exports.writeDot = exports.writeSourceCode = exports.convertDot2Svg = exports.writeOutputFiles = void 0;
|
|
7
7
|
const fs_1 = require("fs");
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const sync_1 = __importDefault(require("@aduh95/viz.js/sync"));
|
|
@@ -64,22 +64,22 @@ function convertDot2Svg(dot) {
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
exports.convertDot2Svg = convertDot2Svg;
|
|
67
|
-
function
|
|
68
|
-
const
|
|
69
|
-
const outputFile =
|
|
70
|
-
debug(`About to write
|
|
67
|
+
function writeSourceCode(code, filename = 'source', extension = '.sol') {
|
|
68
|
+
const fileExtension = path_1.default.extname(filename);
|
|
69
|
+
const outputFile = fileExtension === extension ? filename : filename + extension;
|
|
70
|
+
debug(`About to write source code to file ${outputFile}`);
|
|
71
71
|
(0, fs_1.writeFile)(outputFile, code, (err) => {
|
|
72
72
|
if (err) {
|
|
73
|
-
throw new Error(`Failed to write
|
|
73
|
+
throw new Error(`Failed to write source code to file ${outputFile}`, {
|
|
74
74
|
cause: err,
|
|
75
75
|
});
|
|
76
76
|
}
|
|
77
77
|
else {
|
|
78
|
-
console.log(`
|
|
78
|
+
console.log(`Source code written to ${outputFile}`);
|
|
79
79
|
}
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
|
-
exports.
|
|
82
|
+
exports.writeSourceCode = writeSourceCode;
|
|
83
83
|
function writeDot(dot, filename) {
|
|
84
84
|
const dotFilename = changeFileExtension(filename, 'dot');
|
|
85
85
|
debug(`About to write Dot file to ${dotFilename}`);
|