Comparing version 2.5.10 to 2.5.11
import { EtherscanParser } from './parserEtherscan'; | ||
interface DiffOptions { | ||
network: string; | ||
bNetwork?: string; | ||
lineBuffer: number; | ||
summary?: boolean; | ||
} | ||
@@ -20,9 +22,12 @@ interface FlattenAndDiffOptions extends DiffOptions { | ||
contractNameA: string; | ||
contractNameB?: string; | ||
} | ||
export declare const compareVerifiedContracts: (addressA: string, aEtherscanParser: EtherscanParser, addressB: string, bEtherscanParser: EtherscanParser, options: DiffOptions) => Promise<void>; | ||
export declare const compareVerified2Local: (addressA: string, aEtherscanParser: EtherscanParser, localFolders: string[], options: DiffOptions) => Promise<void>; | ||
export declare const compareFlattenContracts: (addressA: string, addressB: string, aEtherscanParser: EtherscanParser, bEtherscanParser: EtherscanParser, options: FlattenAndDiffOptions) => Promise<{ | ||
contractNameA: string; | ||
contractNameB: string; | ||
} | ||
export declare const compareContracts: (addressA: string, addressB: string, etherscanParserA: EtherscanParser, etherscanParserB: EtherscanParser, options: DiffOptions) => Promise<CompareContracts>; | ||
export declare const displayContractNames: (addressA: string, addressB: string, contractNameA: string, contractNameB: string, options: { | ||
network: string; | ||
bNetwork?: string; | ||
}) => void; | ||
}>; | ||
export declare const diffVerified2Local: (addressA: string, etherscanParserA: EtherscanParser, baseFolders: string[], ignoreFilesOrFolders?: string[]) => Promise<CompareContracts>; | ||
export declare const diffVerifiedContracts: (addressA: string, addressB: string, etherscanParserA: EtherscanParser, etherscanParserB: EtherscanParser, options: DiffOptions) => Promise<CompareContracts>; | ||
export declare const displayFileDiffSummary: (fileDiffs: DiffFiles[]) => void; | ||
@@ -32,6 +37,2 @@ export declare const displayFileDiffs: (fileDiffs: DiffFiles[], options?: { | ||
}) => void; | ||
export declare const flattenAndDiff: (addressA: string, addressB: string, aEtherscanParser: EtherscanParser, bEtherscanParser: EtherscanParser, options: FlattenAndDiffOptions) => Promise<{ | ||
contractNameA: string; | ||
contractNameB: string; | ||
}>; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.flattenAndDiff = exports.displayFileDiffs = exports.displayFileDiffSummary = exports.displayContractNames = exports.compareContracts = void 0; | ||
const regEx_1 = require("./utils/regEx"); | ||
exports.displayFileDiffs = exports.displayFileDiffSummary = exports.diffVerifiedContracts = exports.diffVerified2Local = exports.compareFlattenContracts = exports.compareVerified2Local = exports.compareVerifiedContracts = void 0; | ||
const clc = require('cli-color'); | ||
const fs_1 = require("fs"); | ||
const path_1 = require("path"); | ||
const parserFiles_1 = require("./parserFiles"); | ||
const writerFiles_1 = require("./writerFiles"); | ||
const regEx_1 = require("./utils/regEx"); | ||
const diff_1 = require("./utils/diff"); | ||
const compareContracts = async (addressA, addressB, etherscanParserA, etherscanParserB, options) => { | ||
const debug = require('debug')('sol2uml'); | ||
const compareVerifiedContracts = async (addressA, aEtherscanParser, addressB, bEtherscanParser, options) => { | ||
const { contractNameA, contractNameB, files } = await (0, exports.diffVerifiedContracts)(addressA, addressB, aEtherscanParser, bEtherscanParser, options); | ||
if (!options.summary) { | ||
(0, exports.displayFileDiffs)(files, options); | ||
} | ||
console.log(`Compared the "${contractNameA}" contract with address ${addressA} on ${options.network}`); | ||
console.log(`to the "${contractNameB}" contract with address ${addressB} on ${options.bNetwork || options.network}\n`); | ||
(0, exports.displayFileDiffSummary)(files); | ||
}; | ||
exports.compareVerifiedContracts = compareVerifiedContracts; | ||
const compareVerified2Local = async (addressA, aEtherscanParser, localFolders, options) => { | ||
// compare verified contract to local files | ||
const { contractNameA, files } = await (0, exports.diffVerified2Local)(addressA, aEtherscanParser, localFolders); | ||
if (!options.summary) { | ||
(0, exports.displayFileDiffs)(files, options); | ||
} | ||
console.log(`Compared the "${contractNameA}" contract with address ${addressA} on ${options.network}`); | ||
console.log(`to local files under folders "${localFolders}"\n`); | ||
(0, exports.displayFileDiffSummary)(files); | ||
}; | ||
exports.compareVerified2Local = compareVerified2Local; | ||
const compareFlattenContracts = async (addressA, addressB, aEtherscanParser, bEtherscanParser, options) => { | ||
// Get verified Solidity code from Etherscan and flatten | ||
const { solidityCode: codeA, contractName: contractNameA } = await aEtherscanParser.getSolidityCode(addressA, options.aFile); | ||
const { solidityCode: codeB, contractName: contractNameB } = await bEtherscanParser.getSolidityCode(addressB, options.bFile || options.aFile); | ||
(0, diff_1.diffCode)(codeA, codeB, options.lineBuffer); | ||
if (options.saveFiles) { | ||
await (0, writerFiles_1.writeSolidity)(codeA, addressA); | ||
await (0, writerFiles_1.writeSolidity)(codeB, addressB); | ||
} | ||
console.log(`Compared the flattened "${contractNameA}" contract with address ${addressA} on ${options.network}`); | ||
console.log(`to the flattened "${contractNameB}" contract with address ${addressB} on ${options.bNetwork || options.network}\n`); | ||
return { contractNameA, contractNameB }; | ||
}; | ||
exports.compareFlattenContracts = compareFlattenContracts; | ||
const diffVerified2Local = async (addressA, etherscanParserA, baseFolders, ignoreFilesOrFolders = []) => { | ||
const files = []; | ||
// Get all the source files for the verified contract from Etherscan | ||
const { files: aFiles, contractName: contractNameA } = await etherscanParserA.getSourceCode(addressA); | ||
const bFiles = await (0, parserFiles_1.getSolidityFilesFromFolderOrFiles)(baseFolders, ignoreFilesOrFolders); | ||
// For each file in the A contract | ||
for (const aFile of aFiles) { | ||
// Look for A contract filename in local filesystem | ||
let bFile; | ||
// for each of the base folders | ||
for (const baseFolder of baseFolders) { | ||
bFile = bFiles.find((bFile) => { | ||
const resolvedPath = (0, path_1.resolve)(process.cwd(), baseFolder, aFile.filename); | ||
return bFile === resolvedPath; | ||
}); | ||
if (bFile) { | ||
break; | ||
} | ||
} | ||
if (bFile) { | ||
try { | ||
debug(`Matched verified file ${aFile.filename} to local file ${bFile}`); | ||
// Try and read code from bFile | ||
const bCode = (0, fs_1.readFileSync)(bFile, 'utf8'); | ||
// The A contract filename exists in the B contract | ||
if (aFile.code !== bCode) { | ||
// console.log(`${aFile.filename} ${clc.red('different')}:`) | ||
files.push({ | ||
filename: aFile.filename, | ||
aCode: aFile.code, | ||
bCode, | ||
result: 'changed', | ||
}); | ||
} | ||
else { | ||
files.push({ | ||
filename: aFile.filename, | ||
aCode: aFile.code, | ||
bCode, | ||
result: 'match', | ||
}); | ||
} | ||
} | ||
catch (err) { | ||
throw Error(`Failed to read local file ${bFile}`); | ||
} | ||
} | ||
else { | ||
debug(`Failed to find local file for verified files ${aFile.filename}`); | ||
// The A contract filename does not exist in the B contract | ||
files.push({ | ||
filename: aFile.filename, | ||
aCode: aFile.code, | ||
result: 'removed', | ||
}); | ||
} | ||
} | ||
// Sort by filename | ||
return { | ||
files: files.sort((a, b) => a.filename.localeCompare(b.filename)), | ||
contractNameA, | ||
}; | ||
}; | ||
exports.diffVerified2Local = diffVerified2Local; | ||
const diffVerifiedContracts = async (addressA, addressB, etherscanParserA, etherscanParserB, options) => { | ||
const files = []; | ||
const { files: aFiles, contractName: contractNameA } = await etherscanParserA.getSourceCode(addressA); | ||
const { files: bFiles, contractName: contractNameB } = await etherscanParserB.getSourceCode(addressB); | ||
@@ -79,8 +182,3 @@ if (aFiles.length === 1 && bFiles.length === 1) { | ||
}; | ||
exports.compareContracts = compareContracts; | ||
const displayContractNames = (addressA, addressB, contractNameA, contractNameB, options) => { | ||
console.log(`Contract A: ${addressA} ${contractNameA} on ${options.network}`); | ||
console.log(`Contract B: ${addressB} ${contractNameB} on ${options.bNetwork || options.network}\n`); | ||
}; | ||
exports.displayContractNames = displayContractNames; | ||
exports.diffVerifiedContracts = diffVerifiedContracts; | ||
const displayFileDiffSummary = (fileDiffs) => { | ||
@@ -122,16 +220,2 @@ for (const file of fileDiffs) { | ||
exports.displayFileDiffs = displayFileDiffs; | ||
const flattenAndDiff = async (addressA, addressB, aEtherscanParser, bEtherscanParser, options) => { | ||
// Get verified Solidity code from Etherscan and flatten | ||
const { solidityCode: codeA, contractName: contractNameA } = await aEtherscanParser.getSolidityCode(addressA, options.aFile); | ||
const { solidityCode: codeB, contractName: contractNameB } = await bEtherscanParser.getSolidityCode(addressB, options.bFile || options.aFile); | ||
(0, exports.displayContractNames)(addressA, addressB, contractNameA, contractNameB, options); | ||
(0, diff_1.diffCode)(codeA, codeB, options.lineBuffer); | ||
if (options.saveFiles) { | ||
await (0, writerFiles_1.writeSolidity)(codeA, addressA); | ||
await (0, writerFiles_1.writeSolidity)(codeB, addressB); | ||
} | ||
(0, exports.displayContractNames)(addressA, addressB, contractNameA, contractNameB, options); | ||
return { contractNameA, contractNameB }; | ||
}; | ||
exports.flattenAndDiff = flattenAndDiff; | ||
//# sourceMappingURL=diffContracts.js.map |
@@ -60,3 +60,3 @@ "use strict"; | ||
.on('end', () => { | ||
debug(`Got Solidity files to be parsed: ${files}`); | ||
// debug(`Got Solidity files to be parsed: ${files}`) | ||
resolve(files); | ||
@@ -63,0 +63,0 @@ }); |
@@ -50,4 +50,4 @@ #! /usr/bin/env node | ||
\t\t\t\t When a folder is used, all *.sol files in that folder and all sub folders are used. | ||
\t\t\t\t A comma-separated list of files and folders can also be used. For example | ||
\t\t\t\t\tsol2uml contracts,node_modules/openzeppelin-solidity | ||
\t\t\t\t A comma-separated list of files and folders can also be used. For example, | ||
\t\t\t\t\tsol2uml contracts,node_modules/@openzeppelin | ||
\t\t\t\t If an Ethereum address with a 0x prefix is passed, the verified source code from Etherscan will be used. For example | ||
@@ -222,4 +222,4 @@ \t\t\t\t\tsol2uml 0x79fEbF6B9F76853EDBcBc913e6aAE8232cFB9De9`; | ||
.command('diff') | ||
.usage('[options] <addressA> <addressB>') | ||
.description(`Compare verified Solidity code differences between two contracts. | ||
.usage('[options] <addressA> <addressB or comma-separated folders>') | ||
.description(`Compare verified Solidity code to another verified contract or local source files. | ||
@@ -231,4 +231,6 @@ The results show the comparison of contract A to B. | ||
.argument('<addressA>', 'Contract address in hexadecimal format with a 0x prefix of the first contract', validators_1.validateAddress) | ||
.argument('<addressB>', 'Contract address in hexadecimal format with a 0x prefix of the second contract', validators_1.validateAddress) | ||
.option('-l, --lineBuffer <value>', 'Minimum number of lines before and after changes (default: 4)', validators_1.validateLineBuffer) | ||
.argument('<addressB_folders>', `Location of the contract source code to compare against. Can be a contract address or comma-separated list of local folders. | ||
For example, 0x1091588Cc431275F99DC5Df311fd8E1Ab81c89F3 will get the verified source code from Etherscan | ||
or ".,node_modules" will compare against local files in the current folder and the node_modules folder.`) | ||
.option('-s, --summary', 'Only show a summary of the file differences', false) | ||
.option('-af --aFile <value>', 'Contract A source code filename without the .sol extension (default: compares all source files)') | ||
@@ -239,8 +241,8 @@ .option('-bf --bFile <value>', 'Contract B source code filename without the .sol extension (default: aFile if specified)') | ||
.option('-bk, --bApiKey <key>', 'Blockchain explorer API key for contract B if on a different blockchain to contract A. Contract A uses the `apiKey` option (default: value of `apiKey` option)') | ||
.option('-s, --summary', 'Only show a summary of the file differences', false) | ||
.option('--flatten', 'Flatten into a single file before comparing', false) | ||
.option('--flatten', 'Flatten into a single file before comparing. Only works when comparing two verified contracts, not to local files', false) | ||
.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) | ||
.action(async (addressA, addressB, options, command) => { | ||
.option('-l, --lineBuffer <value>', 'Minimum number of lines before and after changes (default: 4)', validators_1.validateLineBuffer) | ||
.action(async (addressA, addressB_folders, options, command) => { | ||
try { | ||
debug(`About to diff ${addressA} and ${addressB}`); | ||
debug(`About to compare ${addressA} to ${addressB_folders}`); | ||
const combinedOptions = { | ||
@@ -251,20 +253,16 @@ ...command.parent._optionValues, | ||
const aEtherscanParser = new parserEtherscan_1.EtherscanParser(combinedOptions.apiKey, combinedOptions.network, combinedOptions.explorerUrl); | ||
const bEtherscanParser = new parserEtherscan_1.EtherscanParser(combinedOptions.bApiKey || combinedOptions.apiKey, combinedOptions.bNetwork || combinedOptions.network, combinedOptions.bExplorerUrl || combinedOptions.explorerUrl); | ||
if (options.flatten || options.aFile) { | ||
await (0, diffContracts_1.flattenAndDiff)(addressA, addressB, aEtherscanParser, bEtherscanParser, combinedOptions); | ||
if ((0, regEx_1.isAddress)(addressB_folders)) { | ||
const addressB = addressB_folders; | ||
const bEtherscanParser = new parserEtherscan_1.EtherscanParser(combinedOptions.bApiKey || combinedOptions.apiKey, combinedOptions.bNetwork || combinedOptions.network, combinedOptions.bExplorerUrl || combinedOptions.explorerUrl); | ||
// If flattening or just comparing a single file | ||
if (options.flatten || options.aFile) { | ||
await (0, diffContracts_1.compareFlattenContracts)(addressA, addressB, aEtherscanParser, bEtherscanParser, combinedOptions); | ||
} | ||
else { | ||
await (0, diffContracts_1.compareVerifiedContracts)(addressA, aEtherscanParser, addressB, bEtherscanParser, combinedOptions); | ||
} | ||
} | ||
else { | ||
const { contractNameA, contractNameB, files } = await (0, diffContracts_1.compareContracts)(addressA, addressB, aEtherscanParser, bEtherscanParser, combinedOptions); | ||
(0, diffContracts_1.displayContractNames)(addressA, addressB, contractNameA, contractNameB, combinedOptions); | ||
(0, diffContracts_1.displayFileDiffSummary)(files); | ||
if (!options.summary) { | ||
// Just show the summary if all the files are the same | ||
const diffFiles = files.filter((f) => f.result !== 'match'); | ||
if (diffFiles.length === 0) | ||
return; | ||
console.log(); | ||
(0, diffContracts_1.displayFileDiffs)(files, combinedOptions); | ||
(0, diffContracts_1.displayContractNames)(addressA, addressB, contractNameA, contractNameB, combinedOptions); | ||
(0, diffContracts_1.displayFileDiffSummary)(files); | ||
} | ||
const localFolders = addressB_folders.split(','); | ||
await (0, diffContracts_1.compareVerified2Local)(addressA, aEtherscanParser, localFolders, combinedOptions); | ||
} | ||
@@ -271,0 +269,0 @@ } |
{ | ||
"name": "sol2uml", | ||
"version": "2.5.10", | ||
"version": "2.5.11", | ||
"description": "Solidity contract visualisation tool.", | ||
@@ -5,0 +5,0 @@ "main": "./lib/index.js", |
@@ -71,21 +71,21 @@ # Solidity 2 UML | ||
Commands: | ||
class [options] <fileFolderAddress> Generates a UML class diagram from Solidity source code. | ||
storage [options] <fileFolderAddress> Visually display a contract's storage slots. | ||
class [options] <fileFolderAddress> Generates a UML class diagram from Solidity source code. | ||
storage [options] <fileFolderAddress> Visually display a contract's storage slots. | ||
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. | ||
flatten <contractAddress> Merges verified source files for a contract from a Blockchain explorer into one local file. | ||
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. | ||
flatten <contractAddress> Merges verified source files for a contract from a Blockchain explorer into one local Solidity file. | ||
In order for the merged code to compile, the following is done: | ||
1. pragma solidity is set using the compiler of the verified contract. | ||
2. All pragma solidity lines in the source files are commented out. | ||
3. File imports are commented out. | ||
4. "SPDX-License-Identifier" is renamed to "SPDX--License-Identifier". | ||
5. Contract dependencies are analysed so the files are merged in an order that will compile. | ||
diff [options] <addressA> <addressB> Compare verified Solidity code differences between two contracts. | ||
In order for the merged code to compile, the following is done: | ||
1. pragma solidity is set using the compiler of the verified contract. | ||
2. All pragma solidity lines in the source files are commented out. | ||
3. File imports are commented out. | ||
4. "SPDX-License-Identifier" is renamed to "SPDX--License-Identifier". | ||
5. Contract dependencies are analysed so the files are merged in an order that will compile. | ||
diff [options] <addressA> <addressB_folders> Compare verified Solidity code to another verified contract or local source files. | ||
The results show the comparison of contract A to B. | ||
The green sections are additions to contract B that are not in contract A. | ||
The red sections are removals from contract A that are not in contract B. | ||
The line numbers are from contract B. There are no line numbers for the red sections as they are not in contract B. | ||
help [command] display help for command | ||
The results show the comparison of contract A to B. | ||
The green sections are additions to contract B that are not in contract A. | ||
The red sections are removals from contract A that are not in contract B. | ||
The line numbers are from contract B. There are no line numbers for the red sections as they are not in contract B. | ||
help [command] display help for command | ||
``` | ||
@@ -103,4 +103,4 @@ | ||
When a folder is used, all *.sol files in that folder and all sub folders are used. | ||
A comma-separated list of files and folders can also be used. For example | ||
sol2uml contracts,node_modules/openzeppelin-solidity | ||
A comma-separated list of files and folders can also be used. For example, | ||
sol2uml contracts,node_modules/@openzeppelin | ||
If an Ethereum address with a 0x prefix is passed, the verified source code from Etherscan will be used. For example | ||
@@ -185,5 +185,5 @@ sol2uml 0x79fEbF6B9F76853EDBcBc913e6aAE8232cFB9De9 | ||
``` | ||
Usage: sol2uml diff [options] <addressA> <addressB> | ||
Usage: sol2uml diff [options] <addressA> <addressB or comma-separated folders> | ||
Compare verified Solidity code differences between two contracts. | ||
Compare verified Solidity code to another verified contract or local source files. | ||
@@ -197,15 +197,17 @@ The results show the comparison of contract A to B. | ||
addressA Contract address in hexadecimal format with a 0x prefix of the first contract | ||
addressB Contract address in hexadecimal format with a 0x prefix of the second contract | ||
addressB_folders Location of the contract source code to compare against. Can be a contract address or comma-separated list of local folders. | ||
For example, 0x1091588Cc431275F99DC5Df311fd8E1Ab81c89F3 will get the verified source code from Etherscan | ||
or ".,node_modules" will compare against local files in the current folder and the node_modules folder. | ||
Options: | ||
-l, --lineBuffer <value> Minimum number of lines before and after changes (default: 4) | ||
-s, --summary Only show a summary of the file differences (default: false) | ||
-af --aFile <value> Contract A source code filename without the .sol extension (default: compares all source files) | ||
-bf --bFile <value> Contract B source code filename without the .sol extension (default: aFile if specified) | ||
-bn, --bNetwork <network> Ethereum network which maps to a blockchain explorer for contract B if on a different blockchain to contract A. Contract A uses the `network` option (default: value of `network` option) (choices: "mainnet", | ||
"goerli", "sepolia", "polygon", "arbitrum", "avalanche", "bsc", "crono", "fantom", "moonbeam", "optimism", "gnosis", "celo") | ||
-bn, --bNetwork <network> Ethereum network which maps to a blockchain explorer for contract B if on a different blockchain to contract A. Contract A uses the `network` option (default: value of `network` option) (choices: "mainnet", "goerli", "sepolia", "polygon", "arbitrum", "avalanche", | ||
"bsc", "crono", "fantom", "moonbeam", "optimism", "gnosis", "celo") | ||
-be, --bExplorerUrl <url> Override the `bNetwork` option with custom blockchain explorer API URL for contract B if on a different blockchain to contract A. Contract A uses the `explorerUrl` (default: value of `explorerUrl` option) | ||
-bk, --bApiKey <key> Blockchain explorer API key for contract B if on a different blockchain to contract A. Contract A uses the `apiKey` option (default: value of `apiKey` option) | ||
-s, --summary Only show a summary of the file differences. (default: false) | ||
--flatten Flatten into a single file before comparing (default: false) | ||
--flatten Flatten into a single file before comparing. Only works when comparing two verified contracts, not to local files (default: false) | ||
--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 (default: false) | ||
-l, --lineBuffer <value> Minimum number of lines before and after changes (default: 4) | ||
-h, --help display help for command | ||
@@ -212,0 +214,0 @@ ``` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
251233
4922
373
5