From 1057fbd0a7fe23cf7e4ac10ab3deef6405f778f9 Mon Sep 17 00:00:00 2001 From: Eli Leers Date: Thu, 7 Nov 2024 17:50:11 -0800 Subject: [PATCH 01/20] Separate analysis from Markdown printing --- .vscode/settings.json | 2 +- src/analyze.ts | 69 ++------------------ src/main.ts | 25 ++++++-- src/markdown.ts | 106 +++++++++++++++++++++++++++++++ src/types.ts | 14 +++++ tsconfig.json | 3 +- yarn.lock | 142 ++++++++++++++++++++++++++++++++++++++++-- 7 files changed, 284 insertions(+), 77 deletions(-) create mode 100644 src/markdown.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index e6bc7fb..9d7a720 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,6 +4,6 @@ "editor.defaultFormatter": "esbenp.prettier-vscode" }, "editor.codeActionsOnSave": { - "source.fixAll": true + "source.fixAll": "explicit" } } diff --git a/src/analyze.ts b/src/analyze.ts index 322f18c..52fdbc1 100644 --- a/src/analyze.ts +++ b/src/analyze.ts @@ -1,4 +1,4 @@ -import { InputType, Instance, Issue, IssueTypes } from './types'; +import { InputType, Instance, Issue, Analysis } from './types'; import { lineFromIndex } from './utils'; const issueTypesTitles = { @@ -13,9 +13,9 @@ const issueTypesTitles = { * @notice Runs the given issues on files and generate the report markdown string * @param githubLink optional url to generate links */ -const analyze = (files: InputType, issues: Issue[], githubLink?: string): string => { +const analyze = (files: InputType, issues: Issue[], githubLink?: string): Analysis[] => { let result = ''; - let analyze: { issue: Issue; instances: Instance[] }[] = []; + let analyze: Analysis[] = []; for (const issue of issues) { let instances: Instance[] = []; // If issue is a regex @@ -61,68 +61,7 @@ const analyze = (files: InputType, issues: Issue[], githubLink?: string): string } } - /** Summary */ - let c = 0; - if (analyze.length > 0) { - result += `\n## ${issueTypesTitles[analyze[0].issue.type]}\n\n`; - result += '\n| |Issue|Instances|\n|-|:-|:-:|\n'; - for (const { issue, instances } of analyze) { - c++; - result += `| [${issue.type}-${c}](#${issue.type}-${c}) | ${issue.title} | ${instances.length} |\n`; - } - } - - /** Issue breakdown */ - c = 0; - for (const { issue, instances } of analyze) { - c++; - result += `### [${issue.type}-${c}] ${issue.title}\n`; - if (!!issue.description) { - result += `${issue.description}\n`; - } - if (!!issue.impact) { - result += '\n#### Impact:\n'; - result += `${issue.impact}\n`; - } - result += `\n*Instances (${instances.length})*:\n`; - let previousFileName = ''; - for (const o of instances.sort((a, b) => { - if (a.fileName < b.fileName) return -1; - if (a.fileName > b.fileName) return 1; - return !!a.line && !!b.line && a.line < b.line ? -1 : 1; - })) { - if (o.fileName !== previousFileName) { - if (previousFileName !== '') { - result += `\n${'```'}\n`; - if (!!githubLink) { - result += `[Link to code](${githubLink + previousFileName})\n`; - } - result += `\n`; - } - result += `${'```'}solidity\nFile: ${o.fileName}\n`; - previousFileName = o.fileName; - } - - // Insert code snippet - const lineSplit = o.fileContent?.split('\n'); - const offset = o.line.toString().length; - result += `\n${o.line}: ${lineSplit[o.line - 1]}\n`; - if (!!o.endLine) { - let currentLine = o.line + 1; - while (currentLine <= o.endLine) { - result += `${' '.repeat(offset)} ${lineSplit[currentLine - 1]}\n`; - currentLine++; - } - } - } - result += `\n${'```'}\n`; - if (!!githubLink) { - result += `[Link to code](${githubLink + previousFileName})\n`; - } - result += `\n`; - } - - return result; + return analyze; }; export default analyze; diff --git a/src/main.ts b/src/main.ts index 81fa57a..f539f32 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,8 +1,9 @@ -import fs from 'fs'; +import * as fs from 'fs'; import analyze from './analyze'; import compileAndBuildAST from './compile'; import issues from './issues'; -import { InputType, IssueTypes } from './types'; +import markdown from './markdown'; +import { InputType, IssueTypes, Analysis, AnalysisResults } from './types'; import { recursiveExploration } from './utils'; /* .---. ,--. ,-- / ,---. ,--. ,--.' ,-. .----. ,------.,------, @@ -28,7 +29,7 @@ const main = async ( out: string, scope?: string, ) => { - let result = '# Report\n\n'; + // let result = '# Report\n\n'; let fileNames: string[] = []; if (!!scopeFile || !!scope) { @@ -48,6 +49,7 @@ const main = async ( console.log('Scope: ', fileNames); // Uncomment next lines to have the list of analyzed files in the report + // todo: parameterize this // result += '## Files analyzed\n\n'; // fileNames.forEach(fileName => { @@ -65,15 +67,28 @@ const main = async ( }); }); + let analysisResultsObj: AnalysisResults = {}; + + // todo: parameterize which issue types to run for (const t of Object.values(IssueTypes)) { - result += analyze( + let analyses: Analysis[] = analyze( files, issues.filter(i => i.type === t), !!githubLink ? githubLink : undefined, ); + + // add analyze results for this issue type to the results object + analysisResultsObj[t] = analyses; } + + // Do markdown conversion + + let markdownResult = markdown(analysisResultsObj); + + console.log(markdownResult) + - fs.writeFileSync(out, result); + fs.writeFileSync(out, markdownResult); }; export default main; diff --git a/src/markdown.ts b/src/markdown.ts new file mode 100644 index 0000000..4ba20ac --- /dev/null +++ b/src/markdown.ts @@ -0,0 +1,106 @@ +import { InputType, Instance, Issue, IssueTypes, Analysis, AnalysisResults } from './types'; + +// Titles for different issue types +const issueTypesTitles = { + GAS: 'Gas Optimizations', + NC: 'Informational Issues', + L: 'Low Issues', + M: 'Medium Issues', + H: 'High Issues', +}; + + +const markdown = (results: AnalysisResults, fileNames?: string[], githubLink?: string): string => { + let report = '# Report\n\n'; + + fileNames ??= []; + + if (fileNames.length > 0) { + report += files(fileNames); + } + + for (const t of Object.values(IssueTypes)) { + let analyses: Analysis[] = results[t] ?? []; + if(analyses.length > 0) { + report += markdownPerType(analyses, githubLink); + } + } + + return report; +} + +const files = (fileNames: string[]): string => { + let result = '## Files analyzed\n\n'; + fileNames.forEach(fileName => { + result += ` - ${fileName}\n`; + }); + return result; +} + +const markdownPerType = (analyze: Analysis[], githubLink?: string): string => { + let result = ""; + + /** Summary */ + let c = 0; + + result += `\n## ${issueTypesTitles[analyze[0].issue.type]}\n\n`; + result += '\n| |Issue|Instances|\n|-|:-|:-:|\n'; + for (const { issue, instances } of analyze) { + c++; + result += `| [${issue.type}-${c}](#${issue.type}-${c}) | ${issue.title} | ${instances.length} |\n`; + } + + /** Issue breakdown */ + c = 0; + for (const { issue, instances } of analyze) { + c++; + result += `### [${issue.type}-${c}] ${issue.title}\n`; + if (!!issue.description) { + result += `${issue.description}\n`; + } + if (!!issue.impact) { + result += '\n#### Impact:\n'; + result += `${issue.impact}\n`; + } + result += `\n*Instances (${instances.length})*:\n`; + let previousFileName = ''; + for (const o of instances.sort((a, b) => { + if (a.fileName < b.fileName) return -1; + if (a.fileName > b.fileName) return 1; + return !!a.line && !!b.line && a.line < b.line ? -1 : 1; + })) { + if (o.fileName !== previousFileName) { + if (previousFileName !== '') { + result += `\n${'```'}\n`; + if (!!githubLink) { + result += `[Link to code](${githubLink + previousFileName})\n`; + } + result += `\n`; + } + result += `${'```'}solidity\nFile: ${o.fileName}\n`; + previousFileName = o.fileName; + } + + // Insert code snippet + const lineSplit = o.fileContent?.split('\n'); + const offset = o.line.toString().length; + result += `\n${o.line}: ${lineSplit[o.line - 1]}\n`; + if (!!o.endLine) { + let currentLine = o.line + 1; + while (currentLine <= o.endLine) { + result += `${' '.repeat(offset)} ${lineSplit[currentLine - 1]}\n`; + currentLine++; + } + } + } + result += `\n${'```'}\n`; + if (!!githubLink) { + result += `[Link to code](${githubLink + previousFileName})\n`; + } + result += `\n`; + } + + return result; +} + +export default markdown; \ No newline at end of file diff --git a/src/types.ts b/src/types.ts index e8c9ee1..92bb47b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -43,3 +43,17 @@ export type ASTIssue = { detector: (files: InputType) => Instance[]; // Function analyzing the AST and returning instances of the issue regexOrAST: 'AST'; }; + +// Type to bundle Issues and Instances for splitting Analysis and Printing steps +export type Analysis = { + issue: Issue; + instances: Instance[]; +}; + +export type AnalysisResults = { + GAS?: Analysis[]; + NC?: Analysis[]; + L?: Analysis[]; + M?: Analysis[]; + H?: Analysis[]; +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index e9c8ff5..8d300e5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,5 +5,6 @@ }, "compilerOptions": { "noImplicitAny": false - } + }, + "js/ts.implicitProjectConfig.target": "ES2024" } diff --git a/yarn.lock b/yarn.lock index 5f8b273..c9ed7e5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -327,6 +327,11 @@ commander@3.0.2: resolved "https://registry.yarnpkg.com/commander/-/commander-3.0.2.tgz#6837c3fb677ad9933d1cfba42dd14d5117d6b39e" integrity sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow== +commander@^11.0.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-11.1.0.tgz#62fdce76006a68e5c1ab3314dc92e800eb83d906" + integrity sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ== + commander@^8.1.0: version "8.3.0" resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" @@ -1235,6 +1240,11 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +n@^9.2.0: + version "9.2.3" + resolved "https://registry.yarnpkg.com/n/-/n-9.2.3.tgz#dc63618449e40474c74d412d0c14950013c8273c" + integrity sha512-iKU/fMITB+bJe0wQ6Q6THSWBpfF/f/g4elhr23Mp4TywSY0rJvaHVdkMhL9uWEdwdipAPidmTIqafI0BTJj/lQ== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -1883,7 +1893,7 @@ slash@^3.0.0: semver "^5.5.0" tmp "0.0.33" -"solc-0.8.17@npm:solc@0.8.17", solc@^0.8.17: +"solc-0.8.17@npm:solc@0.8.17": version "0.8.17" resolved "https://registry.yarnpkg.com/solc/-/solc-0.8.17.tgz#c748fec6a64bf029ec406aa9b37e75938d1115ae" integrity sha512-Dtidk2XtTTmkB3IKdyeg6wLYopJnBVxdoykN8oP8VY3PQjN16BScYoUJTXFm2OP7P0hXNAqWiJNmmfuELtLf8g== @@ -1896,6 +1906,100 @@ slash@^3.0.0: semver "^5.5.0" tmp "0.0.33" +"solc-0.8.18@npm:solc@0.8.18": + version "0.8.18" + resolved "https://registry.yarnpkg.com/solc/-/solc-0.8.18.tgz#a05ce8918540eda5f10aa91f0f52f239b9645dad" + integrity sha512-wVAa2Y3BYd64Aby5LsgS3g6YC2NvZ3bJ+A8TAIAukfVuQb3AjyGrLZpyxQk5YLn14G35uZtSnIgHEpab9klOLQ== + dependencies: + command-exists "^1.2.8" + commander "^8.1.0" + follow-redirects "^1.12.1" + js-sha3 "0.8.0" + memorystream "^0.3.1" + semver "^5.5.0" + tmp "0.0.33" + +"solc-0.8.19@npm:solc@0.8.19": + version "0.8.19" + resolved "https://registry.yarnpkg.com/solc/-/solc-0.8.19.tgz#cac6541106ae3cff101c740042c7742aa56a2ed3" + integrity sha512-yqurS3wzC4LdEvmMobODXqprV4MYJcVtinuxgrp61ac8K2zz40vXA0eSAskSHPgv8dQo7Nux39i3QBsHx4pqyA== + dependencies: + command-exists "^1.2.8" + commander "^8.1.0" + follow-redirects "^1.12.1" + js-sha3 "0.8.0" + memorystream "^0.3.1" + semver "^5.5.0" + tmp "0.0.33" + +"solc-0.8.1@npm:solc@0.8.1": + version "0.8.1" + resolved "https://registry.yarnpkg.com/solc/-/solc-0.8.1.tgz#cbdba8fea6fbfae463f382cecb59c51de0269472" + integrity sha512-rqB8wlL20I/k+ibCgNGqXaoXBngKTUb3JCsCazwEvxJ9C9RcXNGRsiqgB1xZs37IjINMp0E3xGiuMjGYTBQnUg== + dependencies: + command-exists "^1.2.8" + commander "3.0.2" + follow-redirects "^1.12.1" + fs-extra "^0.30.0" + js-sha3 "0.8.0" + memorystream "^0.3.1" + require-from-string "^2.0.0" + semver "^5.5.0" + tmp "0.0.33" + +"solc-0.8.20@npm:solc@0.8.20": + version "0.8.20" + resolved "https://registry.yarnpkg.com/solc/-/solc-0.8.20.tgz#b49151cf5ecc8de088d3d32b0afb607b3522ba8d" + integrity sha512-fPRnGspIEqmhu63RFO3pc79sLA7ZmzO0Uy0L5l6hEt2wAsq0o7UV6pXkAp3Mfv9IBhg7Px/oTu3a+y4gs3BWrQ== + dependencies: + command-exists "^1.2.8" + commander "^8.1.0" + follow-redirects "^1.12.1" + js-sha3 "0.8.0" + memorystream "^0.3.1" + semver "^5.5.0" + tmp "0.0.33" + +"solc-0.8.21@npm:solc@0.8.21": + version "0.8.21" + resolved "https://registry.yarnpkg.com/solc/-/solc-0.8.21.tgz#c3cd505c360ea2fa0eaa5ab574ef96bffb1a2766" + integrity sha512-N55ogy2dkTRwiONbj4e6wMZqUNaLZkiRcjGyeafjLYzo/tf/IvhHY5P5wpe+H3Fubh9idu071i8eOGO31s1ylg== + dependencies: + command-exists "^1.2.8" + commander "^8.1.0" + follow-redirects "^1.12.1" + js-sha3 "0.8.0" + memorystream "^0.3.1" + semver "^5.5.0" + tmp "0.0.33" + +"solc-0.8.22@npm:solc@0.8.22": + version "0.8.22" + resolved "https://registry.yarnpkg.com/solc/-/solc-0.8.22.tgz#6df0bb688b9a58bbf10932730301374a6ccfb862" + integrity sha512-bA2tMZXx93R8L5LUH7TlB/f+QhkVyxrrY6LmgJnFFZlRknrhYVlBK1e3uHIdKybwoFabOFSzeaZjPeL/GIpFGQ== + dependencies: + command-exists "^1.2.8" + commander "^8.1.0" + follow-redirects "^1.12.1" + js-sha3 "0.8.0" + memorystream "^0.3.1" + semver "^5.5.0" + tmp "0.0.33" + +"solc-0.8.23@npm:solc@0.8.23": + version "0.8.23" + resolved "https://registry.yarnpkg.com/solc/-/solc-0.8.23.tgz#bfbb8ac7f7fcc7db95faf5d709edf15c4f006d89" + integrity sha512-uqe69kFWfJc3cKdxj+Eg9CdW1CP3PLZDPeyJStQVWL8Q9jjjKD0VuRAKBFR8mrWiq5A7gJqERxJFYJsklrVsfA== + dependencies: + command-exists "^1.2.8" + commander "^8.1.0" + follow-redirects "^1.12.1" + js-sha3 "0.8.0" + memorystream "^0.3.1" + n "^9.2.0" + semver "^5.5.0" + tmp "0.0.33" + "solc-0.8.2@npm:solc@0.8.2": version "0.8.2" resolved "https://registry.yarnpkg.com/solc/-/solc-0.8.2.tgz#6033d75c6166fd0feb7fe08eddc198aaf52025da" @@ -1971,6 +2075,21 @@ slash@^3.0.0: semver "^5.5.0" tmp "0.0.33" +"solc-0.8.7@npm:solc@0.8.7": + version "0.8.7" + resolved "https://registry.yarnpkg.com/solc/-/solc-0.8.7.tgz#54434959cc3d69a569ad8853c0d9ee1338da0aab" + integrity sha512-p8Zi+YcGN22P3Stb6KJhNypD9xSnNF3D6eIw6LyxZpMIVpcwrG8fTaXeEbKITmlp14DC1iZ4BC4aV7r7gJ/EJw== + dependencies: + command-exists "^1.2.8" + commander "3.0.2" + follow-redirects "^1.12.1" + fs-extra "^0.30.0" + js-sha3 "0.8.0" + memorystream "^0.3.1" + require-from-string "^2.0.0" + semver "^5.5.0" + tmp "0.0.33" + "solc-0.8.8@npm:solc@0.8.8": version "0.8.8" resolved "https://registry.yarnpkg.com/solc/-/solc-0.8.8.tgz#3902c496cc200fc83bf96ff42d798f3f41c9c489" @@ -2001,10 +2120,23 @@ slash@^3.0.0: semver "^5.5.0" tmp "0.0.33" -solidity-ast@^0.4.35: - version "0.4.35" - resolved "https://registry.yarnpkg.com/solidity-ast/-/solidity-ast-0.4.35.tgz#82e064b14dc989338123264bde2235cad751f128" - integrity sha512-F5bTDLh3rmDxRmLSrs3qt3nvxJprWSEkS7h2KmuXDx7XTfJ6ZKVTV1rtPIYCqJAuPsU/qa8YUeFn7jdOAZcTPA== +solc@^0.8.17: + version "0.8.17" + resolved "https://registry.yarnpkg.com/solc/-/solc-0.8.17.tgz#c748fec6a64bf029ec406aa9b37e75938d1115ae" + integrity sha512-Dtidk2XtTTmkB3IKdyeg6wLYopJnBVxdoykN8oP8VY3PQjN16BScYoUJTXFm2OP7P0hXNAqWiJNmmfuELtLf8g== + dependencies: + command-exists "^1.2.8" + commander "^8.1.0" + follow-redirects "^1.12.1" + js-sha3 "0.8.0" + memorystream "^0.3.1" + semver "^5.5.0" + tmp "0.0.33" + +solidity-ast@^0.4.53: + version "0.4.59" + resolved "https://registry.yarnpkg.com/solidity-ast/-/solidity-ast-0.4.59.tgz#290a2815aef70a61092591ab3e991da080ae5931" + integrity sha512-I+CX0wrYUN9jDfYtcgWSe+OAowaXy8/1YQy7NS4ni5IBDmIYBq7ZzaP/7QqouLjzZapmQtvGLqCaYgoUWqBo5g== spdx-correct@^3.0.0: version "3.1.1" From bb768c1cbbcc5e9a0a38105cdd2badf0a9c62720 Mon Sep 17 00:00:00 2001 From: Eli Leers Date: Thu, 7 Nov 2024 17:53:18 -0800 Subject: [PATCH 02/20] Remove console log of markdown --- src/main.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main.ts b/src/main.ts index f539f32..fa6057c 100644 --- a/src/main.ts +++ b/src/main.ts @@ -82,12 +82,8 @@ const main = async ( } // Do markdown conversion - let markdownResult = markdown(analysisResultsObj); - console.log(markdownResult) - - fs.writeFileSync(out, markdownResult); }; From e906b23fdbb1ca3891f0a908387c010b06d78257 Mon Sep 17 00:00:00 2001 From: Eli Leers Date: Thu, 7 Nov 2024 17:53:32 -0800 Subject: [PATCH 03/20] Remove broken detector --- src/issues/NC/uselessOverride.ts | 61 -------------------------------- 1 file changed, 61 deletions(-) delete mode 100644 src/issues/NC/uselessOverride.ts diff --git a/src/issues/NC/uselessOverride.ts b/src/issues/NC/uselessOverride.ts deleted file mode 100644 index aea1929..0000000 --- a/src/issues/NC/uselessOverride.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { findAll } from 'solidity-ast/utils'; -import { ASTIssue, InputType, Instance, IssueTypes, RegexIssue } from '../../types'; -import { instanceFromSRC } from '../../utils'; -import util from 'util'; - -const issue: ASTIssue = { - regexOrAST: 'AST', - type: IssueTypes.NC, - title: - '`override` function arguments that are unused should have the variable name removed or commented out to avoid compiler warnings', - detector: (files: InputType): Instance[] => { - let instances: Instance[] = []; - - for (const file of files) { - for (const cd of findAll('ContractDefinition', file.ast)) { - if (cd.contractKind == 'interface' || cd.abstract) { - continue; - } - for (const a of findAll('FunctionDefinition', file.ast)) { - if (a.kind == 'constructor' || a.virtual || a.kind == 'fallback' || a.kind == 'receive') { - continue; - } - if (!a.body) { - continue; - } - if (!!a.overrides) { - for (const b of findAll('ParameterList', a)) { - if (a.returnParameters && a.returnParameters.id == b.id) { - continue; - } - for (const b1 of findAll('VariableDeclaration', b)) { - let usesParam = false; - if (!b1.name) { - continue; - } - for (const c of findAll('Block', a)) { - for (const d of findAll('Identifier', c)) { - if (b1.name == d.name) { - usesParam = true; - break; - } - } - if (usesParam) { - break; - } - } - - if (!usesParam) { - instances.push(instanceFromSRC(file, b1.src)); - } - } - } - } - } - } - } - return instances; - }, -}; - -export default issue; From 58837ca44d4ae43960c8f586ed035e46c076c7fc Mon Sep 17 00:00:00 2001 From: Eli Leers Date: Wed, 13 Nov 2024 14:51:32 -0800 Subject: [PATCH 04/20] Fix recursive exploration of directories ending in .sol --- src/utils.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utils.ts b/src/utils.ts index 3cde76b..a1f0250 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -53,10 +53,10 @@ export const recursiveExploration = (basePath: string, extension = '.sol'): stri let tempFileNames = fs.readdirSync(`${basePath}${dir}`); for (let fileName of tempFileNames) { fileName = `${dir}${fileName}`; - if (fileName.endsWith(extension)) { - fileNames.push(fileName); - } else if (fs.statSync(`${basePath}${fileName}`).isDirectory()) { + if (fs.statSync(`${basePath}${fileName}`).isDirectory()) { directoryQueue.push(fileName + '/'); + } else if (fileName.endsWith(extension)) { + fileNames.push(fileName); } } } From 1e1daad63562fb6b10986acc45529e93dd9eeb77 Mon Sep 17 00:00:00 2001 From: Eli Leers Date: Thu, 14 Nov 2024 10:26:52 -0800 Subject: [PATCH 05/20] Sarif support --- src/index.ts | 20 ++++++- src/main.ts | 22 +++++-- src/sarif.ts | 165 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/types.ts | 4 ++ 4 files changed, 204 insertions(+), 7 deletions(-) create mode 100644 src/sarif.ts diff --git a/src/index.ts b/src/index.ts index cade67e..9933f0d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,12 +9,28 @@ import main from './main'; // ================================= PARAMETERS ================================ +// process parameter flags +const argv = key => { + // Return true if the key exists and a value is undefined + // if ( process.argv.includes( `--${ key }` ) ) return true; + + const value = process.argv.find( element => element.startsWith( `--${ key }=` ) ); + + // Return undefined if the key does not exist and a value is undefined + if ( !value ) return undefined; + + return value.replace( `--${ key }=` , '' ); +} + const basePath = process.argv.length > 2 ? (process.argv[2].endsWith('/') ? process.argv[2] : process.argv[2] + '/') : 'contracts/'; const scopeFile = process.argv.length > 3 && process.argv[3].endsWith('txt') ? process.argv[3] : null; const githubLink = process.argv.length > 4 && process.argv[4] ? process.argv[4] : null; -const out = 'report.md'; +const out = argv("out") ?? 'report.md'; +const scope = argv("scope"); +const sarif = argv("sarif"); + // ============================== GENERATE REPORT ============================== -main(basePath, scopeFile, githubLink, out); +main(basePath, scopeFile, githubLink, out, scope, 'sarif.sarif'); diff --git a/src/main.ts b/src/main.ts index fa6057c..4733fb9 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,9 +1,10 @@ import * as fs from 'fs'; import analyze from './analyze'; +import sarif from './sarif'; import compileAndBuildAST from './compile'; import issues from './issues'; import markdown from './markdown'; -import { InputType, IssueTypes, Analysis, AnalysisResults } from './types'; +import { InputType, IssueTypes, Analysis, AnalysisResults, ReportTypes } from './types'; import { recursiveExploration } from './utils'; /* .---. ,--. ,-- / ,---. ,--. ,--.' ,-. .----. ,------.,------, @@ -28,8 +29,8 @@ const main = async ( githubLink: string | null, out: string, scope?: string, + sarifOut?: string ) => { - // let result = '# Report\n\n'; let fileNames: string[] = []; if (!!scopeFile || !!scope) { @@ -80,11 +81,22 @@ const main = async ( // add analyze results for this issue type to the results object analysisResultsObj[t] = analyses; } - - // Do markdown conversion - let markdownResult = markdown(analysisResultsObj); + // Do markdown conversion + let markdownResult = markdown(analysisResultsObj, fileNames); fs.writeFileSync(out, markdownResult); + + if(sarifOut){ + let sarifAnalyses: Analysis[] = []; + + for (const t of Object.values(IssueTypes)) { + sarifAnalyses = sarifAnalyses.concat((analysisResultsObj[t] ?? [])); + } + + let sarifResult = sarif(sarifAnalyses); + + fs.writeFileSync(sarifOut, JSON.stringify(sarifResult, null, 2), 'utf-8'); + } }; export default main; diff --git a/src/sarif.ts b/src/sarif.ts new file mode 100644 index 0000000..845b91f --- /dev/null +++ b/src/sarif.ts @@ -0,0 +1,165 @@ +import { Analysis } from './types'; + + +// Titles for different issue types +const issueTypesTitles = { + GAS: 'Gas Optimizations', + NC: 'Informational Issues', + L: 'Low Issues', + M: 'Medium Issues', + H: 'High Issues', +}; + +// Function to convert a string to Pascal-case +const toPascalCase = (str: string) => { + return str + .replace(/[^a-zA-Z0-9 ]/g, '') // Remove non-alphanumeric characters + .replace(/\w\S*/g, (txt) => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase()) // Capitalize each word + .replace(/\s+/g, ''); // Remove spaces +}; + +const sanitizeFileName = (fileName: string) => { + return fileName.replace(/^\.?\//, ''); +}; + +// Function to sanitize file names by removing leading "." and "/" +const sanitizeFileNames = (fileName: string) => { + return fileName.replace(/^\.?\//, ''); +}; + +// Function to map issue types to SARIF severity levels +const mapSeverity = (type: string) => { + switch (type) { + case 'NC': + return 'note'; + case 'G': + return 'note'; + case 'GAS': + return 'note'; + case 'L': + return 'warning'; + case 'M': + return 'warning'; + case 'H': + return 'error'; + default: + return 'note'; + } +}; + +const mapSecuritySeverity = (type: string) => { + switch (type) { + case 'NC': + return '0.0'; // No Severity + case 'G': + return '2.5'; // Low + case 'GAS': + return '2.5'; // Low + case 'L': + return '5.0'; // Medium + case 'M': + return '7.5'; // High + case 'H': + return '10.0'; // Critical + default: + return '10.0'; // Everything should be define + } +}; + +// Function to map issue types to descriptive tags +const mapTag = (type: string) => { + switch (type) { + case 'NC': + return 'Informational'; + case 'G': + return 'Gas Optimization'; + case 'GAS': + return 'Gas Optimization'; + case 'L': + return 'Low'; + case 'M': + return 'Medium'; + case 'H': + return 'High'; + default: + return 'Informational'; + } +}; + +const sarif = (analyses: Analysis[]): Object => { + // Convert the JSON data to SARIF format + console.log(analyses.length); + + const sarifDetails = { + version: "2.1.0", + $schema: "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", + runs: [ + { + tool: { + driver: { + name: "4naly3er", + fullName: "4naly3er Static Smart Contract Code Analyzer", + informationUri: "https://github.com/AnalyticETH/4naly3er", + version: "0.2", // Update the version number + rules: analyses.map((item, index) => ({ + id: `rule${index + 1}`, + name: item.issue.title, + shortDescription: { + text: item.issue.title + }, + fullDescription: { + text: item.issue.description || item.issue.title + }, + helpUri: "https://github.com/AnalyticETH/4naly3er/blob/analytic/detectors.md", + help: { + text: item.issue.description || item.issue.title + }, + properties: { + tags: [mapTag(item.issue.type)], // Map issue type to descriptive tag + "security-severity": mapSecuritySeverity(item.issue.type), // Map issue type to SARIF severity level + "problem.severity": mapSecuritySeverity(item.issue.type) // Map issue type to SARIF severity level + } + })) + } + }, + automationDetails: { + id: "4naly3er" + }, + results: analyses.flatMap((item, index) => + item.instances.map(instance => ({ + ruleId: `rule${index + 1}`, + message: { + text: item.issue.title + }, + locations: [ + { + physicalLocation: { + artifactLocation: { + uri: sanitizeFileNames(instance.fileName), // Sanitize the file name to remove leading "." + }, + region: { + startLine: instance.line, + startColumn: 1 + } + } + } + ], + partialFingerprints: { + primaryLocationLineHash: `${sanitizeFileNames(instance.fileName)}:${instance.line}` // Sanitize file name to remove leading "." + }, + level: mapSeverity(item.issue.type), // Map issue type to SARIF severity level + })) + ) + } + ] + }; + + return sarifDetails; + + + // we should return this instead of writing to fs here + // // Write the SARIF data to a file called report.sarif.json + // fs.writeFileSync('report.sarif.json', JSON.stringify(sarif, null, 2), 'utf-8'); +} + +export default sarif; diff --git a/src/types.ts b/src/types.ts index 92bb47b..309a3cd 100644 --- a/src/types.ts +++ b/src/types.ts @@ -8,6 +8,10 @@ export enum IssueTypes { H = 'H', } +export enum ReportTypes { + markdown = 'markdown' +} + // List of solidity files with content and name export type InputType = { content: string; name: string; ast: SourceUnit }[]; From 8d66b1f45a61761b7dbdd26f46a5401e37074939 Mon Sep 17 00:00:00 2001 From: Eli Leers Date: Thu, 14 Nov 2024 10:27:25 -0800 Subject: [PATCH 06/20] Skip test, script, and lib folders in recursive Exploration --- src/utils.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/utils.ts b/src/utils.ts index a1f0250..1209d81 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -54,7 +54,9 @@ export const recursiveExploration = (basePath: string, extension = '.sol'): stri for (let fileName of tempFileNames) { fileName = `${dir}${fileName}`; if (fs.statSync(`${basePath}${fileName}`).isDirectory()) { - directoryQueue.push(fileName + '/'); + if (fileName != "test" && fileName != "lib" && fileName != "script"){ // skip test and lib folders + directoryQueue.push(fileName + '/'); + } } else if (fileName.endsWith(extension)) { fileNames.push(fileName); } From 9e37445088c8f160b3c0f98b1506ee2bfd6c3485 Mon Sep 17 00:00:00 2001 From: Eli Leers Date: Mon, 18 Nov 2024 13:41:38 -0800 Subject: [PATCH 07/20] Partial Revert of #43 Remove changes to index.ts to support Commander Keep everything else for now --- src/index.ts | 43 ++++++++++++++++++------------------------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/src/index.ts b/src/index.ts index 9933f0d..db9598e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,28 +9,21 @@ import main from './main'; // ================================= PARAMETERS ================================ -// process parameter flags -const argv = key => { - // Return true if the key exists and a value is undefined - // if ( process.argv.includes( `--${ key }` ) ) return true; - - const value = process.argv.find( element => element.startsWith( `--${ key }=` ) ); - - // Return undefined if the key does not exist and a value is undefined - if ( !value ) return undefined; - - return value.replace( `--${ key }=` , '' ); -} - -const basePath = - process.argv.length > 2 ? (process.argv[2].endsWith('/') ? process.argv[2] : process.argv[2] + '/') : 'contracts/'; -const scopeFile = process.argv.length > 3 && process.argv[3].endsWith('txt') ? process.argv[3] : null; -const githubLink = process.argv.length > 4 && process.argv[4] ? process.argv[4] : null; -const out = argv("out") ?? 'report.md'; -const scope = argv("scope"); -const sarif = argv("sarif"); - - -// ============================== GENERATE REPORT ============================== - -main(basePath, scopeFile, githubLink, out, scope, 'sarif.sarif'); +import { program } from 'commander'; + +program + .argument('[string]', 'Path were the contracts lies') + .option('-s, --scope ', '.txt file containing the contest scope') + .option('-g, --github ', 'github url to generate links to code') + .option('-o, --out ', 'where to save the report') + .action((basePath:string, options) => { + basePath = basePath ||'contracts/'; + basePath = basePath.endsWith('/') ? basePath : `${basePath}/`; + console.log(`basePath: ${basePath}`); + console.log(`scope: ${options.scope||'----'}`); + console.log(`github: ${options.github||'----'}`); + console.log(`out: ${options.out||'report.md'}`); + console.log('*****************************') + // ============================== GENERATE REPORT ============================== + main(basePath, options.scope, options.gihub, options.out || 'report.md'); + }).parse(); From 56f2a0669a30159eb7fca52eaa5fa64390a1590b Mon Sep 17 00:00:00 2001 From: Eli Leers Date: Mon, 18 Nov 2024 15:59:04 -0800 Subject: [PATCH 08/20] Commander SARIF support --- src/index.ts | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/index.ts b/src/index.ts index db9598e..01756c0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -12,10 +12,13 @@ import main from './main'; import { program } from 'commander'; program - .argument('[string]', 'Path were the contracts lies') - .option('-s, --scope ', '.txt file containing the contest scope') - .option('-g, --github ', 'github url to generate links to code') - .option('-o, --out ', 'where to save the report') + .argument('[basePath]', 'Path were the contracts lies') + .option('-s, --scope ', '.txt file containing the contest scope') + .option('-g, --github ', 'github url to generate links to code') + .option('-o, --out ', 'Path for Markdown report') + .option('-l, --listfiles', 'List analyzed files in Markdown Report') + .option('--legacyscope ', 'Path for legacy scope file') + .option('--sarif [string]', 'Generate SARIF report, optionally include path to report. Default is analyzer.sarif', ) .action((basePath:string, options) => { basePath = basePath ||'contracts/'; basePath = basePath.endsWith('/') ? basePath : `${basePath}/`; @@ -23,7 +26,15 @@ program console.log(`scope: ${options.scope||'----'}`); console.log(`github: ${options.github||'----'}`); console.log(`out: ${options.out||'report.md'}`); + console.log(`legacyScope: ${options.legacyscope||'----'}`); + console.log(`sarif: ${options.sarif||'----'}`); + + let sarif; + if(options.sarif === undefined) sarif = undefined; + else if(options.sarif === true) sarif = 'analyzer.sarif'; + else sarif = options.sarif; + console.log('*****************************') // ============================== GENERATE REPORT ============================== - main(basePath, options.scope, options.gihub, options.out || 'report.md'); + main(basePath, options.scope, options.github, options.out || 'report.md', options.legacyscope, sarif, options.listfiles); }).parse(); From 1d9f2b2e60e47db357b6c2fd60b4d6d05a988dd7 Mon Sep 17 00:00:00 2001 From: Eli Leers Date: Mon, 18 Nov 2024 16:21:39 -0800 Subject: [PATCH 09/20] parameterize listing files in report --- src/main.ts | 15 +++++---------- src/markdown.ts | 11 +++++++---- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/main.ts b/src/main.ts index 4733fb9..4b812d7 100644 --- a/src/main.ts +++ b/src/main.ts @@ -22,6 +22,8 @@ import { recursiveExploration } from './utils'; * @param githubLink github url to generate links to code * @param out where to save the report * @param scope optional text containing the .sol files in scope. Replaces `scopeFile` + * @param sarif optional string with location to save sarif report. If undefined, SARIF generation is skipped. + * @param listFiles optional boolean, if true list the analyzed files in the markdown report. */ const main = async ( basePath: string, @@ -29,7 +31,8 @@ const main = async ( githubLink: string | null, out: string, scope?: string, - sarifOut?: string + sarifOut?: string, + listFiles?: boolean ) => { let fileNames: string[] = []; @@ -49,14 +52,6 @@ const main = async ( console.log('Scope: ', fileNames); - // Uncomment next lines to have the list of analyzed files in the report - // todo: parameterize this - - // result += '## Files analyzed\n\n'; - // fileNames.forEach(fileName => { - // result += ` - ${fileName}\n`; - // }); - // Read file contents and build AST const files: InputType = []; const asts = await compileAndBuildAST(basePath, fileNames); @@ -83,7 +78,7 @@ const main = async ( } // Do markdown conversion - let markdownResult = markdown(analysisResultsObj, fileNames); + let markdownResult = markdown(analysisResultsObj, listFiles ? fileNames : undefined, githubLink ?? undefined); fs.writeFileSync(out, markdownResult); if(sarifOut){ diff --git a/src/markdown.ts b/src/markdown.ts index 4ba20ac..88eef9e 100644 --- a/src/markdown.ts +++ b/src/markdown.ts @@ -30,10 +30,13 @@ const markdown = (results: AnalysisResults, fileNames?: string[], githubLink?: s } const files = (fileNames: string[]): string => { - let result = '## Files analyzed\n\n'; - fileNames.forEach(fileName => { - result += ` - ${fileName}\n`; - }); + let result = '' + if (fileNames.length > 0){ + result = '## Files analyzed\n\n'; + fileNames.forEach(fileName => { + result += ` - ${fileName}\n`; + }); + } return result; } From b31be9fb2e421304c5955aef10240bc8e177f819 Mon Sep 17 00:00:00 2001 From: Eli Leers Date: Tue, 19 Nov 2024 15:57:27 -0800 Subject: [PATCH 10/20] remove fingerprint temporarily --- src/sarif.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sarif.ts b/src/sarif.ts index 845b91f..889b8e8 100644 --- a/src/sarif.ts +++ b/src/sarif.ts @@ -144,9 +144,9 @@ const sarif = (analyses: Analysis[]): Object => { } } ], - partialFingerprints: { - primaryLocationLineHash: `${sanitizeFileNames(instance.fileName)}:${instance.line}` // Sanitize file name to remove leading "." - }, + // partialFingerprints: { + // primaryLocationLineHash: `${sanitizeFileNames(instance.fileName)}:${instance.line}` // Sanitize file name to remove leading "." + // }, level: mapSeverity(item.issue.type), // Map issue type to SARIF severity level })) ) From af76dd5145b04d06e4f3e350f2d27e0c716c0f06 Mon Sep 17 00:00:00 2001 From: Eli Leers Date: Thu, 23 Jan 2025 13:30:06 -0800 Subject: [PATCH 11/20] Sarif Regex Deduplication --- src/sarif.ts | 106 ++++++++++++++++++++++++++++++++++++--------------- src/types.ts | 24 +++++++++++- 2 files changed, 98 insertions(+), 32 deletions(-) diff --git a/src/sarif.ts b/src/sarif.ts index 889b8e8..b5af911 100644 --- a/src/sarif.ts +++ b/src/sarif.ts @@ -1,4 +1,4 @@ -import { Analysis } from './types'; +import { Analysis, SARIFResult, Instance, Location } from './types'; // Titles for different issue types @@ -86,6 +86,79 @@ const mapTag = (type: string) => { } }; +const generateResults = (analyses: Analysis[]) => { + const results = analyses.flatMap((item, index) => { + if(item.issue.regexOrAST === 'Regex') { + // Regex Results need to be deduplicated for matching files + + let RegexResults: SARIFResult[] = []; + + const FileIssueMap: { [key: string]: Instance[] } = {}; // Map of file names to instances + item.instances.forEach(issue => { // Populate the map + if (!FileIssueMap[issue.fileName]) { + FileIssueMap[issue.fileName] = []; + } + FileIssueMap[issue.fileName].push(issue); + }); + + Object.keys(FileIssueMap).forEach(key => { // For each file, create a SARIFResult + let locations: Location[] = []; + FileIssueMap[key].forEach(issue => { + locations.push({ + physicalLocation: { + artifactLocation: { + uri: sanitizeFileNames(issue.fileName), // Sanitize the file name to remove leading "." + }, + region: { + startLine: issue.line, + startColumn: 1, + ...(issue.endLine && { endLine: issue.endLine }) // Add endLine if it exists + } + } + }); + }); + let fileResult: SARIFResult = { + ruleId: `rule${index + 1}`, + message: { + text: item.issue.title + }, + locations: locations, + level: mapSeverity(item.issue.type), // Map issue type to SARIF severity level + }; + RegexResults.push(fileResult); + }); + + return RegexResults; + + } else if (item.issue.regexOrAST === 'AST') { // AST Results use default locations + return item.instances.map(instance => ({ + ruleId: `rule${index + 1}`, + message: { + text: item.issue.title + }, + locations: [ + { + physicalLocation: { + artifactLocation: { + uri: sanitizeFileNames(instance.fileName), // Sanitize the file name to remove leading "." + }, + region: { + startLine: instance.line, + startColumn: 1, + ...(instance.endLine && { endLine: instance.endLine }) // Add endLine if it exists + } + } + } + ], + level: mapSeverity(item.issue.type), // Map issue type to SARIF severity level + })); + } + } + ); + + return results; +} + const sarif = (analyses: Analysis[]): Object => { // Convert the JSON data to SARIF format console.log(analyses.length); @@ -125,41 +198,12 @@ const sarif = (analyses: Analysis[]): Object => { automationDetails: { id: "4naly3er" }, - results: analyses.flatMap((item, index) => - item.instances.map(instance => ({ - ruleId: `rule${index + 1}`, - message: { - text: item.issue.title - }, - locations: [ - { - physicalLocation: { - artifactLocation: { - uri: sanitizeFileNames(instance.fileName), // Sanitize the file name to remove leading "." - }, - region: { - startLine: instance.line, - startColumn: 1 - } - } - } - ], - // partialFingerprints: { - // primaryLocationLineHash: `${sanitizeFileNames(instance.fileName)}:${instance.line}` // Sanitize file name to remove leading "." - // }, - level: mapSeverity(item.issue.type), // Map issue type to SARIF severity level - })) - ) + results: generateResults(analyses) } ] }; return sarifDetails; - - - // we should return this instead of writing to fs here - // // Write the SARIF data to a file called report.sarif.json - // fs.writeFileSync('report.sarif.json', JSON.stringify(sarif, null, 2), 'utf-8'); } export default sarif; diff --git a/src/types.ts b/src/types.ts index 309a3cd..c6c7122 100644 --- a/src/types.ts +++ b/src/types.ts @@ -60,4 +60,26 @@ export type AnalysisResults = { L?: Analysis[]; M?: Analysis[]; H?: Analysis[]; -} \ No newline at end of file +} + +export type SARIFResult = { + ruleId: string; + message: { + text: string; + }; + locations: Location[]; + level: string; +}; + +export type Location = { + physicalLocation: { + artifactLocation: { + uri: string; + }; + region: { + startLine: number; + startColumn: number; + endLine?: number; + }; + }; +}; \ No newline at end of file From 84ee38a927b8ae4a1552a0496f74c75ca487fbf6 Mon Sep 17 00:00:00 2001 From: Eli Leers Date: Wed, 29 Jan 2025 14:14:21 -0800 Subject: [PATCH 12/20] severity filtering --- src/index.ts | 29 +++++++++++++++++++++-------- src/main.ts | 8 ++++---- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/index.ts b/src/index.ts index 01756c0..e87922d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,6 +10,7 @@ import main from './main'; // ================================= PARAMETERS ================================ import { program } from 'commander'; +import { IssueTypes } from './types'; program .argument('[basePath]', 'Path were the contracts lies') @@ -18,23 +19,35 @@ program .option('-o, --out ', 'Path for Markdown report') .option('-l, --listfiles', 'List analyzed files in Markdown Report') .option('--legacyscope ', 'Path for legacy scope file') - .option('--sarif [string]', 'Generate SARIF report, optionally include path to report. Default is analyzer.sarif', ) + .option('--sarif [outputPath]', 'Generate SARIF report, optionally include path to report. Default is analyzer.sarif') + .option('--skip-info', 'Skip info issues') + .option('--skip-gas', 'Skip gas issues') + .option('--skip-low', 'Skip low issues') + .option('--skip-medium', 'Skip medium issues') + .option('--skip-high', 'Skip high issues') .action((basePath:string, options) => { basePath = basePath ||'contracts/'; basePath = basePath.endsWith('/') ? basePath : `${basePath}/`; + + const sarif = options.sarif === true ? 'analyzer.sarif' : options.sarif; + + const severityToRun: IssueTypes[] = []; + if(!options.skipInfo) severityToRun.push(IssueTypes.NC); + if(!options.skipGas) severityToRun.push(IssueTypes.GAS); + if(!options.skipLow) severityToRun.push(IssueTypes.L); + if(!options.skipMedium) severityToRun.push(IssueTypes.M); + if(!options.skipHigh) severityToRun.push(IssueTypes.H); + console.log(`basePath: ${basePath}`); console.log(`scope: ${options.scope||'----'}`); console.log(`github: ${options.github||'----'}`); console.log(`out: ${options.out||'report.md'}`); console.log(`legacyScope: ${options.legacyscope||'----'}`); console.log(`sarif: ${options.sarif||'----'}`); - - let sarif; - if(options.sarif === undefined) sarif = undefined; - else if(options.sarif === true) sarif = 'analyzer.sarif'; - else sarif = options.sarif; + console.log(`severityMinimum: ${options.severityMinimum||'0'}`); + console.log('Severity to run: ', severityToRun); console.log('*****************************') - // ============================== GENERATE REPORT ============================== - main(basePath, options.scope, options.github, options.out || 'report.md', options.legacyscope, sarif, options.listfiles); + // ============================== RUN ANALYZER ============================== + main(basePath, options.scope, options.github, options.out || 'report.md', severityToRun, options.legacyscope, options.sarif, options.listfiles); }).parse(); diff --git a/src/main.ts b/src/main.ts index 4b812d7..3819e60 100644 --- a/src/main.ts +++ b/src/main.ts @@ -4,7 +4,7 @@ import sarif from './sarif'; import compileAndBuildAST from './compile'; import issues from './issues'; import markdown from './markdown'; -import { InputType, IssueTypes, Analysis, AnalysisResults, ReportTypes } from './types'; +import { InputType, IssueTypes, Analysis, AnalysisResults, ReportTypes, Issue } from './types'; import { recursiveExploration } from './utils'; /* .---. ,--. ,-- / ,---. ,--. ,--.' ,-. .----. ,------.,------, @@ -30,9 +30,10 @@ const main = async ( scopeFile: string | null, githubLink: string | null, out: string, + severityToRun: IssueTypes[], scope?: string, sarifOut?: string, - listFiles?: boolean + listFiles?: boolean, ) => { let fileNames: string[] = []; @@ -65,8 +66,7 @@ const main = async ( let analysisResultsObj: AnalysisResults = {}; - // todo: parameterize which issue types to run - for (const t of Object.values(IssueTypes)) { + for (const t of severityToRun) { let analyses: Analysis[] = analyze( files, issues.filter(i => i.type === t), From dd29a4b8af9a419c0d8cfff3b6c754edf2b8b0c0 Mon Sep 17 00:00:00 2001 From: Eli Leers Date: Wed, 29 Jan 2025 15:08:22 -0800 Subject: [PATCH 13/20] Add support for skipping detectors --- src/index.ts | 8 ++++++-- src/main.ts | 3 ++- src/types.ts | 2 ++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/index.ts b/src/index.ts index e87922d..7ba6855 100644 --- a/src/index.ts +++ b/src/index.ts @@ -25,6 +25,7 @@ program .option('--skip-low', 'Skip low issues') .option('--skip-medium', 'Skip medium issues') .option('--skip-high', 'Skip high issues') + .option('--skip, --skip-detectors [detectorID...]', 'Skip specific detectors by id') .action((basePath:string, options) => { basePath = basePath ||'contracts/'; basePath = basePath.endsWith('/') ? basePath : `${basePath}/`; @@ -38,16 +39,19 @@ program if(!options.skipMedium) severityToRun.push(IssueTypes.M); if(!options.skipHigh) severityToRun.push(IssueTypes.H); + const skipDetectors = options.skip || []; + const skipDetectorsLower = skipDetectors.map(detector => detector.toLowerCase()); // Convert to lowercase to avoid case-sensitive issues + console.log(`basePath: ${basePath}`); console.log(`scope: ${options.scope||'----'}`); console.log(`github: ${options.github||'----'}`); console.log(`out: ${options.out||'report.md'}`); console.log(`legacyScope: ${options.legacyscope||'----'}`); console.log(`sarif: ${options.sarif||'----'}`); - console.log(`severityMinimum: ${options.severityMinimum||'0'}`); console.log('Severity to run: ', severityToRun); + console.log('Skipping detectors: ', skipDetectorsLower); console.log('*****************************') // ============================== RUN ANALYZER ============================== - main(basePath, options.scope, options.github, options.out || 'report.md', severityToRun, options.legacyscope, options.sarif, options.listfiles); + main(basePath, options.scope, options.github, options.out || 'report.md', severityToRun, skipDetectorsLower, options.legacyscope, options.sarif, options.listfiles); }).parse(); diff --git a/src/main.ts b/src/main.ts index 3819e60..cde1011 100644 --- a/src/main.ts +++ b/src/main.ts @@ -31,6 +31,7 @@ const main = async ( githubLink: string | null, out: string, severityToRun: IssueTypes[], + skipDetectors: string[], scope?: string, sarifOut?: string, listFiles?: boolean, @@ -69,7 +70,7 @@ const main = async ( for (const t of severityToRun) { let analyses: Analysis[] = analyze( files, - issues.filter(i => i.type === t), + issues.filter(i => i.type === t && !skipDetectors.includes(i.id.toLowerCase())), !!githubLink ? githubLink : undefined, ); diff --git a/src/types.ts b/src/types.ts index c6c7122..323ba70 100644 --- a/src/types.ts +++ b/src/types.ts @@ -27,6 +27,7 @@ export type Issue = RegexIssue | ASTIssue; // Type to follow to add an issue detected by a regex export type RegexIssue = { + id: string; type: IssueTypes; title: string; regex: RegExp; @@ -40,6 +41,7 @@ export type RegexIssue = { // Type to follow to add an issue detected by AST analysis export type ASTIssue = { + id: string; type: IssueTypes; title: string; impact?: string; From 6806e5bb8ab0301102c18c689d4a1d73b8dd29b0 Mon Sep 17 00:00:00 2001 From: Eli Leers Date: Wed, 29 Jan 2025 15:08:58 -0800 Subject: [PATCH 14/20] Add IDs to each detector based on filename --- src/issues/GAS/ERC721A.ts | 1 + src/issues/GAS/_msgSender.ts | 1 + src/issues/GAS/addPlusEqual.ts | 1 + src/issues/GAS/addressZero.ts | 1 + src/issues/GAS/assignUpdateArray.ts | 1 + src/issues/GAS/boolCompare.ts | 1 + src/issues/GAS/boolIncursOverhead.ts | 1 + src/issues/GAS/cacheArrayLength.ts | 1 + src/issues/GAS/cacheVariable.ts | 1 + src/issues/GAS/calldataViewFunctions.ts | 1 + src/issues/GAS/canUseUnchecked.ts | 1 + src/issues/GAS/customErrors.ts | 1 + src/issues/GAS/delegatecallAddressCheck.ts | 1 + src/issues/GAS/dontCacheIfUsedOnce.ts | 1 + src/issues/GAS/immutableConstructor.ts | 1 + src/issues/GAS/initializeDefaultValue.ts | 1 + src/issues/GAS/longRevertString.ts | 1 + src/issues/GAS/payableFunctions.ts | 1 + src/issues/GAS/postIncrement.ts | 1 + src/issues/GAS/privateForConstants.ts | 1 + src/issues/GAS/shiftInsteadOfDiv.ts | 1 + src/issues/GAS/splitRequireStatement.ts | 1 + src/issues/GAS/superfluousEventField.ts | 1 + src/issues/GAS/thisExternal.ts | 1 + src/issues/GAS/uintBoolBitMaps.ts | 1 + src/issues/GAS/uncheckedIncrements.ts | 1 + src/issues/GAS/unsignedComparison.ts | 1 + src/issues/GAS/uselessInternal.ts | 1 + src/issues/GAS/wethHardcode.ts | 1 + src/issues/H/comparisonOutsideCondition.ts | 1 + src/issues/H/delegateCallInLoop.ts | 1 + src/issues/H/get_dy_underlyingFlashLoan.ts | 1 + src/issues/H/msg.valueInLoop.ts | 1 + src/issues/H/wstETHPriceStEth.ts | 1 + src/issues/L/2stepowner.ts | 1 + src/issues/L/MultiplicationBeforeDivision.ts | 1 + src/issues/L/NFTNoHandleHardForks.ts | 1 + src/issues/L/SomeERC20TransferRevertsOn0.ts | 1 + src/issues/L/address0Check.ts | 1 + src/issues/L/avoidEcrecover.ts | 1 + src/issues/L/avoidEncodePacked.ts | 1 + src/issues/L/avoidTxOrigin.ts | 1 + src/issues/L/calc_token_amountAlreadyHasSlippage.ts | 1 + src/issues/L/decimalsNotERC20.ts | 1 + src/issues/L/decimalsNotUint8.ts | 1 + src/issues/L/deprecatedApprove.ts | 1 + src/issues/L/deprecatedFunctions.ts | 1 + src/issues/L/deprecatedSafeApprove.ts | 1 + src/issues/L/deprecatedSetupRole.ts | 1 + src/issues/L/disableInitImpl.ts | 1 + src/issues/L/div0NotPrevented.ts | 1 + src/issues/L/domainSeparatorReplayAttack.ts | 1 + src/issues/L/duplicateImports.ts | 1 + src/issues/L/emptyBody.ts | 1 + src/issues/L/emptyFallbackRequire.ts | 1 + src/issues/L/extCallLoop.ts | 1 + src/issues/L/extCallRecipientGas.ts | 1 + src/issues/L/fallBackLackPayable.ts | 1 + src/issues/L/frontRunnableInitializer.ts | 1 + src/issues/L/includeTimestampAtDeadline.ts | 1 + src/issues/L/lackSlippage.ts | 1 + src/issues/L/mathmaxInt.ts | 1 + src/issues/L/mintAndBurnAddress0.ts | 1 + src/issues/L/nftOwnershipHardfork.ts | 1 + src/issues/L/ownerRenounceDuringPause.ts | 1 + src/issues/L/possibleRounding.ts | 1 + src/issues/L/pragmaExpDeprecated.ts | 1 + src/issues/L/precisionLoss.ts | 1 + src/issues/L/push0Solc0820.ts | 1 + src/issues/L/safeTransferOwnership.ts | 1 + src/issues/L/solc1314OptimizerBug.ts | 1 + src/issues/L/sweepingRescuing.ts | 1 + src/issues/L/symbolNotERC20.ts | 1 + src/issues/L/unsafeCasting.ts | 1 + src/issues/L/unsafeERC20Operations.ts | 1 + src/issues/L/unsafeReturnBomb.ts | 1 + src/issues/L/unspecifiedPragma.ts | 1 + src/issues/L/upgradeableMissingGap.ts | 1 + src/issues/L/upgradeableNotInit.ts | 1 + src/issues/L/useOfEcrecover.ts | 1 + src/issues/L/useOnlyInitializing.ts | 1 + src/issues/L/year365.ts | 1 + src/issues/M/FoTTokens.ts | 1 + src/issues/M/NFTRedefinesMint.ts | 1 + src/issues/M/approve0first.ts | 1 + src/issues/M/avoidTx.origin.ts | 1 + src/issues/M/blockNumberL2.ts | 1 + src/issues/M/centralizationRisk.ts | 1 + src/issues/M/deprecatedChainlinkFunction.ts | 1 + src/issues/M/deprecatedTransfer.ts | 1 + src/issues/M/erc721safeMint.ts | 1 + src/issues/M/erc721safeTransferFrom.ts | 1 + src/issues/M/feeOver100.ts | 1 + src/issues/M/increaseAllowanceUSDT.ts | 1 + src/issues/M/keccakOnStructOrArray.ts | 1 + src/issues/M/libraryPublicFunction.ts | 1 + src/issues/M/soladySafeTransferLib.ts | 1 + src/issues/M/solmateSafeTransferLib.ts | 1 + src/issues/M/staleOracleData.ts | 1 + src/issues/M/staleOracleDataL2Sequencer.ts | 1 + src/issues/M/supportInterface.ts | 1 + src/issues/M/uncheckedERC20Transfer.ts | 1 + src/issues/M/unsafeERC20Transfer.ts | 1 + src/issues/NC/abiEncodeCall.ts | 1 + src/issues/NC/abicoderv2.ts | 1 + src/issues/NC/address0Check.ts | 1 + src/issues/NC/arrayIndices.ts | 1 + src/issues/NC/assertRequire.ts | 1 + src/issues/NC/concat.ts | 1 + src/issues/NC/constantStyle.ts | 1 + src/issues/NC/constantsInsteadMagic.ts | 1 + src/issues/NC/controlStructureStyle.ts | 1 + src/issues/NC/criticalChange.ts | 1 + src/issues/NC/dangerWhileTrue.ts | 1 + src/issues/NC/defaultVisibility.ts | 1 + src/issues/NC/deleteLogs.ts | 1 + src/issues/NC/disableRenounceOwnership.ts | 1 + src/issues/NC/draft-OZ.ts | 1 + src/issues/NC/duplicateRequireRevert.ts | 1 + src/issues/NC/elseBlockOnReturn.ts | 1 + src/issues/NC/errorneverUsed.ts | 1 + src/issues/NC/eventNeverEmitted.ts | 1 + src/issues/NC/eventNoArgs.ts | 1 + src/issues/NC/eventNotProperlyIndexed.ts | 1 + src/issues/NC/eventOldNew.ts | 1 + src/issues/NC/functionOrdering.ts | 1 + src/issues/NC/functionsTooLong.ts | 1 + src/issues/NC/implicitInt.ts | 1 + src/issues/NC/implicitUint.ts | 1 + src/issues/NC/interfaceInaming.ts | 1 + src/issues/NC/interfaceOwnFile.ts | 1 + src/issues/NC/lackReasonableBounds.ts | 1 + src/issues/NC/linesTooLong.ts | 1 + src/issues/NC/mappingStyle.ts | 1 + src/issues/NC/maxUint.ts | 1 + src/issues/NC/maxUint256.ts | 1 + src/issues/NC/missingEventSetters.ts | 1 + src/issues/NC/missingNatspec.ts | 1 + src/issues/NC/missingNatspecParam.ts | 1 + src/issues/NC/missingNatspecReturn.ts | 1 + src/issues/NC/missingSPDX.ts | 1 + src/issues/NC/modifierForMsgSender.ts | 1 + src/issues/NC/multipleConstantDeclaration.ts | 1 + src/issues/NC/namedMappings.ts | 1 + src/issues/NC/noAddressHardcode.ts | 1 + src/issues/NC/nonReentrantBeforeModifiers.ts | 1 + src/issues/NC/numericTimeDays.ts | 1 + src/issues/NC/onlyConstantsInUppercase.ts | 1 + src/issues/NC/ownerCanRenounceWhilePaused.ts | 1 + src/issues/NC/redundantNamedReturn.ts | 1 + src/issues/NC/requireWithString.ts | 1 + src/issues/NC/revertWithoutArgument.ts | 1 + src/issues/NC/safeMath08.ts | 1 + src/issues/NC/scientificNotationExponent.ts | 1 + src/issues/NC/scientificNotationZeros.ts | 1 + src/issues/NC/sensitiveTerms.ts | 1 + src/issues/NC/stringQuote.ts | 1 + src/issues/NC/style.ts | 1 + src/issues/NC/styleGuide.ts | 1 + src/issues/NC/todoLeftInTheCode.ts | 1 + src/issues/NC/unclearRequire.ts | 1 + src/issues/NC/underscoreDecimals.ts | 1 + src/issues/NC/underscoreInternal.ts | 1 + src/issues/NC/unindexedEvent.ts | 1 + src/issues/NC/useConstants.ts | 1 + src/issues/NC/uselessPublic.ts | 1 + src/issues/NC/uselessZeroInit.ts | 1 + src/issues/NC/v2728check.ts | 1 + 168 files changed, 168 insertions(+) diff --git a/src/issues/GAS/ERC721A.ts b/src/issues/GAS/ERC721A.ts index db9dfc2..ea988ab 100644 --- a/src/issues/GAS/ERC721A.ts +++ b/src/issues/GAS/ERC721A.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'erc721A', regexOrAST: 'Regex', type: IssueTypes.GAS, title: 'Use ERC721A instead ERC721', diff --git a/src/issues/GAS/_msgSender.ts b/src/issues/GAS/_msgSender.ts index bebd52c..449a567 100644 --- a/src/issues/GAS/_msgSender.ts +++ b/src/issues/GAS/_msgSender.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: '_msgSender', regexOrAST: 'Regex', type: IssueTypes.GAS, title: "Don't use `_msgSender()` if not supporting EIP-2771", diff --git a/src/issues/GAS/addPlusEqual.ts b/src/issues/GAS/addPlusEqual.ts index 4d03b69..a6b6757 100644 --- a/src/issues/GAS/addPlusEqual.ts +++ b/src/issues/GAS/addPlusEqual.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'addPlusEqual', regexOrAST: 'Regex', type: IssueTypes.GAS, title: '`a = a + b` is more gas effective than `a += b` for state variables (excluding arrays and mappings)', diff --git a/src/issues/GAS/addressZero.ts b/src/issues/GAS/addressZero.ts index a6851ad..060aff2 100644 --- a/src/issues/GAS/addressZero.ts +++ b/src/issues/GAS/addressZero.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import { Expression, SourceUnit } from 'solidity-ast'; const issue: ASTIssue = { + id: 'addressZero', regexOrAST: 'AST', type: IssueTypes.GAS, title: 'Use assembly to check for `address(0)`', diff --git a/src/issues/GAS/assignUpdateArray.ts b/src/issues/GAS/assignUpdateArray.ts index 47f90b9..7e54e56 100644 --- a/src/issues/GAS/assignUpdateArray.ts +++ b/src/issues/GAS/assignUpdateArray.ts @@ -3,6 +3,7 @@ import { findAll } from 'solidity-ast/utils'; import { instanceFromSRC } from '../../utils'; const issue: ASTIssue = { + id: 'assignUpdateArray', regexOrAST: 'AST', type: IssueTypes.GAS, title: '`array[index] += amount` is cheaper than `array[index] = array[index] + amount` (or related variants)', diff --git a/src/issues/GAS/boolCompare.ts b/src/issues/GAS/boolCompare.ts index aa2c1d8..565a1c5 100644 --- a/src/issues/GAS/boolCompare.ts +++ b/src/issues/GAS/boolCompare.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'boolCompare', regexOrAST: 'Regex', type: IssueTypes.GAS, title: 'Comparing to a Boolean constant', diff --git a/src/issues/GAS/boolIncursOverhead.ts b/src/issues/GAS/boolIncursOverhead.ts index 6010583..af02d50 100644 --- a/src/issues/GAS/boolIncursOverhead.ts +++ b/src/issues/GAS/boolIncursOverhead.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'boolIncursOverhead', regexOrAST: 'Regex', type: IssueTypes.GAS, title: 'Using bools for storage incurs overhead', diff --git a/src/issues/GAS/cacheArrayLength.ts b/src/issues/GAS/cacheArrayLength.ts index 8ea4316..ef189e4 100644 --- a/src/issues/GAS/cacheArrayLength.ts +++ b/src/issues/GAS/cacheArrayLength.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'cacheArrayLength', regexOrAST: 'Regex', type: IssueTypes.GAS, title: 'Cache array length outside of loop', diff --git a/src/issues/GAS/cacheVariable.ts b/src/issues/GAS/cacheVariable.ts index 9c70a4a..0345ba6 100644 --- a/src/issues/GAS/cacheVariable.ts +++ b/src/issues/GAS/cacheVariable.ts @@ -4,6 +4,7 @@ import { getStorageVariable, instanceFromSRC } from '../../utils'; import { Identifier } from 'solidity-ast'; const issue: ASTIssue = { + id: 'cacheVariable', regexOrAST: 'AST', type: IssueTypes.GAS, title: 'State variables should be cached in stack variables rather than re-reading them from storage', diff --git a/src/issues/GAS/calldataViewFunctions.ts b/src/issues/GAS/calldataViewFunctions.ts index a264ba5..13636b4 100644 --- a/src/issues/GAS/calldataViewFunctions.ts +++ b/src/issues/GAS/calldataViewFunctions.ts @@ -3,6 +3,7 @@ import { ASTIssue, InputType, Instance, IssueTypes, RegexIssue } from '../../typ import { instanceFromSRC } from '../../utils'; const issue: ASTIssue = { + id: 'calldataViewFunctions', regexOrAST: 'AST', type: IssueTypes.GAS, title: 'Use calldata instead of memory for function arguments that do not get mutated', diff --git a/src/issues/GAS/canUseUnchecked.ts b/src/issues/GAS/canUseUnchecked.ts index d9c0a6e..88d4588 100644 --- a/src/issues/GAS/canUseUnchecked.ts +++ b/src/issues/GAS/canUseUnchecked.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'canUseUnchecked', regexOrAST: 'Regex', type: IssueTypes.GAS, title: 'For Operations that will not overflow, you could use unchecked', diff --git a/src/issues/GAS/customErrors.ts b/src/issues/GAS/customErrors.ts index 6f1de28..49807fc 100644 --- a/src/issues/GAS/customErrors.ts +++ b/src/issues/GAS/customErrors.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'customErrors', regexOrAST: 'Regex', type: IssueTypes.GAS, title: 'Use Custom Errors instead of Revert Strings to save Gas', diff --git a/src/issues/GAS/delegatecallAddressCheck.ts b/src/issues/GAS/delegatecallAddressCheck.ts index 9b4f36d..1e05693 100644 --- a/src/issues/GAS/delegatecallAddressCheck.ts +++ b/src/issues/GAS/delegatecallAddressCheck.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'delegatecallAddressCheck', regexOrAST: 'Regex', type: IssueTypes.GAS, title: 'Avoid contract existence checks by using low level calls', diff --git a/src/issues/GAS/dontCacheIfUsedOnce.ts b/src/issues/GAS/dontCacheIfUsedOnce.ts index 88e3503..bd25f07 100644 --- a/src/issues/GAS/dontCacheIfUsedOnce.ts +++ b/src/issues/GAS/dontCacheIfUsedOnce.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'dontCacheIfUsedOnce', regexOrAST: 'AST', type: IssueTypes.GAS, title: 'Stack variable used as a cheaper cache for a state variable is only used once', diff --git a/src/issues/GAS/immutableConstructor.ts b/src/issues/GAS/immutableConstructor.ts index 3556a02..a208ec8 100644 --- a/src/issues/GAS/immutableConstructor.ts +++ b/src/issues/GAS/immutableConstructor.ts @@ -4,6 +4,7 @@ import { ASTIssue, InputType, Instance, IssueTypes, RegexIssue } from '../../typ import { instanceFromSRC, topLevelFiles, getStorageVariable } from '../../utils'; const issue: ASTIssue = { + id: 'immutableConstructor', regexOrAST: 'AST', type: IssueTypes.GAS, title: 'State variables only set in the constructor should be declared `immutable`', diff --git a/src/issues/GAS/initializeDefaultValue.ts b/src/issues/GAS/initializeDefaultValue.ts index 7ed425f..e2649c5 100644 --- a/src/issues/GAS/initializeDefaultValue.ts +++ b/src/issues/GAS/initializeDefaultValue.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'initializeDefaultValue', regexOrAST: 'Regex', type: IssueTypes.GAS, title: "Don't initialize variables with default value", diff --git a/src/issues/GAS/longRevertString.ts b/src/issues/GAS/longRevertString.ts index f98aa69..50e5b4b 100644 --- a/src/issues/GAS/longRevertString.ts +++ b/src/issues/GAS/longRevertString.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'longRevertString', regexOrAST: 'Regex', type: IssueTypes.GAS, title: 'Reduce the size of error messages (Long revert Strings)', diff --git a/src/issues/GAS/payableFunctions.ts b/src/issues/GAS/payableFunctions.ts index cef54af..69172b6 100644 --- a/src/issues/GAS/payableFunctions.ts +++ b/src/issues/GAS/payableFunctions.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'payableFunctions', regexOrAST: 'Regex', type: IssueTypes.GAS, title: 'Functions guaranteed to revert when called by normal users can be marked `payable`', diff --git a/src/issues/GAS/postIncrement.ts b/src/issues/GAS/postIncrement.ts index ef91d4b..614adc2 100644 --- a/src/issues/GAS/postIncrement.ts +++ b/src/issues/GAS/postIncrement.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'postIncrement', regexOrAST: 'Regex', type: IssueTypes.GAS, title: '`++i` costs less gas compared to `i++` or `i += 1` (same for `--i` vs `i--` or `i -= 1`)', diff --git a/src/issues/GAS/privateForConstants.ts b/src/issues/GAS/privateForConstants.ts index 0267a11..232863f 100644 --- a/src/issues/GAS/privateForConstants.ts +++ b/src/issues/GAS/privateForConstants.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'privateForConstants', regexOrAST: 'Regex', type: IssueTypes.GAS, title: 'Using `private` rather than `public` for constants, saves gas', diff --git a/src/issues/GAS/shiftInsteadOfDiv.ts b/src/issues/GAS/shiftInsteadOfDiv.ts index d0467dd..152efbb 100644 --- a/src/issues/GAS/shiftInsteadOfDiv.ts +++ b/src/issues/GAS/shiftInsteadOfDiv.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'shiftInsteadOfDiv', regexOrAST: 'Regex', type: IssueTypes.GAS, title: 'Use shift right/left instead of division/multiplication if possible', diff --git a/src/issues/GAS/splitRequireStatement.ts b/src/issues/GAS/splitRequireStatement.ts index b0f705e..02fcce0 100644 --- a/src/issues/GAS/splitRequireStatement.ts +++ b/src/issues/GAS/splitRequireStatement.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'splitRequireStatement', regexOrAST: 'Regex', type: IssueTypes.GAS, title: 'Splitting require() statements that use && saves gas', diff --git a/src/issues/GAS/superfluousEventField.ts b/src/issues/GAS/superfluousEventField.ts index b4339d7..088b3ed 100644 --- a/src/issues/GAS/superfluousEventField.ts +++ b/src/issues/GAS/superfluousEventField.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'superfluousEventField', regexOrAST: 'Regex', type: IssueTypes.GAS, title: 'Superfluous event fields', diff --git a/src/issues/GAS/thisExternal.ts b/src/issues/GAS/thisExternal.ts index ef42ac0..929df17 100644 --- a/src/issues/GAS/thisExternal.ts +++ b/src/issues/GAS/thisExternal.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'thisExternal', regexOrAST: 'Regex', type: IssueTypes.GAS, title: 'Use of `this` instead of marking as `public` an `external` function', diff --git a/src/issues/GAS/uintBoolBitMaps.ts b/src/issues/GAS/uintBoolBitMaps.ts index 0681ed8..7c26970 100644 --- a/src/issues/GAS/uintBoolBitMaps.ts +++ b/src/issues/GAS/uintBoolBitMaps.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'uintBoolBitMaps', regexOrAST: 'Regex', type: IssueTypes.GAS, title: '`uint256` to `bool` `mapping`: Utilizing Bitmaps to dramatically save on Gas', diff --git a/src/issues/GAS/uncheckedIncrements.ts b/src/issues/GAS/uncheckedIncrements.ts index e85c4fd..236c6ea 100644 --- a/src/issues/GAS/uncheckedIncrements.ts +++ b/src/issues/GAS/uncheckedIncrements.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'uncheckedIncrements', regexOrAST: 'Regex', type: IssueTypes.GAS, title: 'Increments/decrements can be unchecked in for-loops', diff --git a/src/issues/GAS/unsignedComparison.ts b/src/issues/GAS/unsignedComparison.ts index 6884d4f..f66b6f1 100644 --- a/src/issues/GAS/unsignedComparison.ts +++ b/src/issues/GAS/unsignedComparison.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'unsignedComparison', regexOrAST: 'Regex', type: IssueTypes.GAS, title: 'Use != 0 instead of > 0 for unsigned integer comparison', diff --git a/src/issues/GAS/uselessInternal.ts b/src/issues/GAS/uselessInternal.ts index 0763fb1..b9695dc 100644 --- a/src/issues/GAS/uselessInternal.ts +++ b/src/issues/GAS/uselessInternal.ts @@ -4,6 +4,7 @@ import { ASTIssue, InputType, Instance, IssueTypes, RegexIssue } from '../../typ import { instanceFromSRC, topLevelFiles } from '../../utils'; const issue: ASTIssue = { + id: 'uselessInternal', regexOrAST: 'AST', type: IssueTypes.GAS, title: '`internal` functions not called by the contract should be removed', diff --git a/src/issues/GAS/wethHardcode.ts b/src/issues/GAS/wethHardcode.ts index 6c817a5..f2370fb 100644 --- a/src/issues/GAS/wethHardcode.ts +++ b/src/issues/GAS/wethHardcode.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'wethHardcode', regexOrAST: 'Regex', type: IssueTypes.GAS, title: 'WETH address definition can be use directly', diff --git a/src/issues/H/comparisonOutsideCondition.ts b/src/issues/H/comparisonOutsideCondition.ts index 6768d65..ac200a4 100644 --- a/src/issues/H/comparisonOutsideCondition.ts +++ b/src/issues/H/comparisonOutsideCondition.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'comparisonOutsideCondition', regexOrAST: 'Regex', type: IssueTypes.H, title: 'Incorrect comparison implementation', diff --git a/src/issues/H/delegateCallInLoop.ts b/src/issues/H/delegateCallInLoop.ts index 895f518..724ffe5 100644 --- a/src/issues/H/delegateCallInLoop.ts +++ b/src/issues/H/delegateCallInLoop.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'delegateCallInLoop', regexOrAST: 'Regex', type: IssueTypes.H, title: 'Using `delegatecall` inside a loop', diff --git a/src/issues/H/get_dy_underlyingFlashLoan.ts b/src/issues/H/get_dy_underlyingFlashLoan.ts index dc6f37f..1cf5764 100644 --- a/src/issues/H/get_dy_underlyingFlashLoan.ts +++ b/src/issues/H/get_dy_underlyingFlashLoan.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'getDyUnderlyingFlashLoan', regexOrAST: 'Regex', type: IssueTypes.H, title: '`get_dy_underlying()` is not a flash-loan-resistant price', diff --git a/src/issues/H/msg.valueInLoop.ts b/src/issues/H/msg.valueInLoop.ts index aa2f8aa..b713392 100644 --- a/src/issues/H/msg.valueInLoop.ts +++ b/src/issues/H/msg.valueInLoop.ts @@ -3,6 +3,7 @@ import { ASTIssue, InputType, Instance, IssueTypes, RegexIssue } from '../../typ import { instanceFromSRC, lineFromIndex } from '../../utils'; const issue: ASTIssue = { + id: 'msgValueInLoop', regexOrAST: 'AST', type: IssueTypes.H, title: 'Using `msg.value` in a loop', diff --git a/src/issues/H/wstETHPriceStEth.ts b/src/issues/H/wstETHPriceStEth.ts index c943b1f..6837320 100644 --- a/src/issues/H/wstETHPriceStEth.ts +++ b/src/issues/H/wstETHPriceStEth.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'wstEthPriceStEth', regexOrAST: 'Regex', type: IssueTypes.H, title: "`wstETH`'s functions operate on units of stEth, not Eth", diff --git a/src/issues/L/2stepowner.ts b/src/issues/L/2stepowner.ts index e51d2b6..0bcfcd7 100644 --- a/src/issues/L/2stepowner.ts +++ b/src/issues/L/2stepowner.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: '2stepowner', regexOrAST: 'Regex', type: IssueTypes.L, title: 'Use a 2-step ownership transfer pattern', diff --git a/src/issues/L/MultiplicationBeforeDivision.ts b/src/issues/L/MultiplicationBeforeDivision.ts index 8a51b65..0812acb 100644 --- a/src/issues/L/MultiplicationBeforeDivision.ts +++ b/src/issues/L/MultiplicationBeforeDivision.ts @@ -3,6 +3,7 @@ import { ASTIssue, InputType, Instance, IssueTypes } from '../../types'; import { instanceFromSRC } from '../../utils'; const issue: ASTIssue = { + id: 'multiplicationBeforeDivision', regexOrAST: 'AST', type: IssueTypes.L, title: 'Precision Loss due to Division before Multiplication', diff --git a/src/issues/L/NFTNoHandleHardForks.ts b/src/issues/L/NFTNoHandleHardForks.ts index 04d2618..25fc914 100644 --- a/src/issues/L/NFTNoHandleHardForks.ts +++ b/src/issues/L/NFTNoHandleHardForks.ts @@ -4,6 +4,7 @@ import { instanceFromSRC, lineFromIndex } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'nftNoHandleHardForks', regexOrAST: 'AST', type: IssueTypes.L, title: 'NFT doesn\'t handle hard forks', diff --git a/src/issues/L/SomeERC20TransferRevertsOn0.ts b/src/issues/L/SomeERC20TransferRevertsOn0.ts index 7195619..f9b7c81 100644 --- a/src/issues/L/SomeERC20TransferRevertsOn0.ts +++ b/src/issues/L/SomeERC20TransferRevertsOn0.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'someERC20TransferRevertsOn0', regexOrAST: 'AST', type: IssueTypes.L, title: 'Some tokens may revert when zero value transfers are made', diff --git a/src/issues/L/address0Check.ts b/src/issues/L/address0Check.ts index 8acf299..ece3e69 100644 --- a/src/issues/L/address0Check.ts +++ b/src/issues/L/address0Check.ts @@ -3,6 +3,7 @@ import { ASTIssue, InputType, Instance, IssueTypes, RegexIssue } from '../../typ import { getStorageVariable, instanceFromSRC } from '../../utils'; const issue: ASTIssue = { + id: 'address0Check', regexOrAST: 'AST', type: IssueTypes.L, title: 'Missing checks for `address(0)` when assigning values to address state variables', diff --git a/src/issues/L/avoidEcrecover.ts b/src/issues/L/avoidEcrecover.ts index 187cb14..4fa1789 100644 --- a/src/issues/L/avoidEcrecover.ts +++ b/src/issues/L/avoidEcrecover.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'avoidEcrecover', regexOrAST: 'Regex', type: IssueTypes.L, title: 'Use of `ecrecover` is susceptible to signature malleability', diff --git a/src/issues/L/avoidEncodePacked.ts b/src/issues/L/avoidEncodePacked.ts index 590ce7a..b7379f5 100644 --- a/src/issues/L/avoidEncodePacked.ts +++ b/src/issues/L/avoidEncodePacked.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'avoidEncodePacked', regexOrAST: 'AST', type: IssueTypes.L, title: diff --git a/src/issues/L/avoidTxOrigin.ts b/src/issues/L/avoidTxOrigin.ts index f5b36a5..7e72961 100644 --- a/src/issues/L/avoidTxOrigin.ts +++ b/src/issues/L/avoidTxOrigin.ts @@ -1,6 +1,7 @@ import {IssueTypes} from "../../types"; const issue = { + id: 'avoidTxOrigin', regexOrAST: 'Regex', type: IssueTypes.L, title: 'Use of `tx.origin` is unsafe in almost every context', diff --git a/src/issues/L/calc_token_amountAlreadyHasSlippage.ts b/src/issues/L/calc_token_amountAlreadyHasSlippage.ts index 40c2268..24c0495 100644 --- a/src/issues/L/calc_token_amountAlreadyHasSlippage.ts +++ b/src/issues/L/calc_token_amountAlreadyHasSlippage.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'calcTokenAmountSlippage', regexOrAST: 'Regex', type: IssueTypes.L, title: '`calc_token_amount()` has slippage added on top of Curve\'s calculated slippage', diff --git a/src/issues/L/decimalsNotERC20.ts b/src/issues/L/decimalsNotERC20.ts index b1f536b..ecd8942 100644 --- a/src/issues/L/decimalsNotERC20.ts +++ b/src/issues/L/decimalsNotERC20.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'decimalsNotERC20', regexOrAST: 'Regex', type: IssueTypes.L, title: '`decimals()` is not a part of the ERC-20 standard', diff --git a/src/issues/L/decimalsNotUint8.ts b/src/issues/L/decimalsNotUint8.ts index e577512..1283d79 100644 --- a/src/issues/L/decimalsNotUint8.ts +++ b/src/issues/L/decimalsNotUint8.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'decimalsNotUint8', regexOrAST: 'Regex', type: IssueTypes.L, title: '`decimals()` should be of type `uint8`', diff --git a/src/issues/L/deprecatedApprove.ts b/src/issues/L/deprecatedApprove.ts index 7585617..5debbfb 100644 --- a/src/issues/L/deprecatedApprove.ts +++ b/src/issues/L/deprecatedApprove.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'deprecatedApprove', regexOrAST: 'AST', type: IssueTypes.L, title: 'Deprecated approve() function', diff --git a/src/issues/L/deprecatedFunctions.ts b/src/issues/L/deprecatedFunctions.ts index c6376be..130b233 100644 --- a/src/issues/L/deprecatedFunctions.ts +++ b/src/issues/L/deprecatedFunctions.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'deprecatedFunctions', regexOrAST: 'Regex', type: IssueTypes.L, title: 'Do not use deprecated library functions', diff --git a/src/issues/L/deprecatedSafeApprove.ts b/src/issues/L/deprecatedSafeApprove.ts index e6e152c..2ad1614 100644 --- a/src/issues/L/deprecatedSafeApprove.ts +++ b/src/issues/L/deprecatedSafeApprove.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'deprecatedSafeApprove', regexOrAST: 'Regex', type: IssueTypes.L, title: '`safeApprove()` is deprecated', diff --git a/src/issues/L/deprecatedSetupRole.ts b/src/issues/L/deprecatedSetupRole.ts index cabc6cf..84fe44f 100644 --- a/src/issues/L/deprecatedSetupRole.ts +++ b/src/issues/L/deprecatedSetupRole.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'deprecatedSetupRole', regexOrAST: 'Regex', type: IssueTypes.L, title: 'Deprecated _setupRole() function', diff --git a/src/issues/L/disableInitImpl.ts b/src/issues/L/disableInitImpl.ts index 052852a..92c794e 100644 --- a/src/issues/L/disableInitImpl.ts +++ b/src/issues/L/disableInitImpl.ts @@ -3,6 +3,7 @@ import { ASTIssue, InputType, Instance, IssueTypes, RegexIssue } from '../../typ import { instanceFromSRC } from '../../utils'; const issue: ASTIssue = { + id: 'disableInitImpl', regexOrAST: 'AST', type: IssueTypes.L, title: 'Do not leave an implementation contract uninitialized', diff --git a/src/issues/L/div0NotPrevented.ts b/src/issues/L/div0NotPrevented.ts index fcd61d5..dde109e 100644 --- a/src/issues/L/div0NotPrevented.ts +++ b/src/issues/L/div0NotPrevented.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'div0NotPrevented', regexOrAST: 'Regex', type: IssueTypes.L, title: 'Division by zero not prevented', diff --git a/src/issues/L/domainSeparatorReplayAttack.ts b/src/issues/L/domainSeparatorReplayAttack.ts index c160264..0e07d34 100644 --- a/src/issues/L/domainSeparatorReplayAttack.ts +++ b/src/issues/L/domainSeparatorReplayAttack.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'domainSeparatorReplayAttack', regexOrAST: 'Regex', type: IssueTypes.L, title: '`domainSeparator()` isn\'t protected against replay attacks in case of a future chain split ', diff --git a/src/issues/L/duplicateImports.ts b/src/issues/L/duplicateImports.ts index 348d20e..c56a28d 100644 --- a/src/issues/L/duplicateImports.ts +++ b/src/issues/L/duplicateImports.ts @@ -5,6 +5,7 @@ import util from 'util'; // regex: /(\{\})|(\{ \})/gi, const issue: ASTIssue = { + id: 'duplicateImports', regexOrAST: 'AST', type: IssueTypes.L, title: 'Duplicate import statements', diff --git a/src/issues/L/emptyBody.ts b/src/issues/L/emptyBody.ts index be7e2ab..a4f9576 100644 --- a/src/issues/L/emptyBody.ts +++ b/src/issues/L/emptyBody.ts @@ -5,6 +5,7 @@ import util from 'util'; // regex: /(\{\})|(\{ \})/gi, const issue: ASTIssue = { + id: 'emptyBody', regexOrAST: 'AST', type: IssueTypes.L, title: 'Empty Function Body - Consider commenting why', diff --git a/src/issues/L/emptyFallbackRequire.ts b/src/issues/L/emptyFallbackRequire.ts index 74234e2..29603c4 100644 --- a/src/issues/L/emptyFallbackRequire.ts +++ b/src/issues/L/emptyFallbackRequire.ts @@ -5,6 +5,7 @@ import util from 'util'; // regex: /(\{\})|(\{ \})/gi, const issue: ASTIssue = { + id: 'emptyFallbackRequire', regexOrAST: 'AST', type: IssueTypes.L, title: 'Empty `receive()/payable fallback()` function does not authenticate requests', diff --git a/src/issues/L/extCallLoop.ts b/src/issues/L/extCallLoop.ts index 653b046..d6f86c9 100644 --- a/src/issues/L/extCallLoop.ts +++ b/src/issues/L/extCallLoop.ts @@ -3,6 +3,7 @@ import { ASTIssue, InputType, Instance, IssueTypes, RegexIssue } from '../../typ import { getStorageVariable, instanceFromSRC } from '../../utils'; const issue: ASTIssue = { + id: 'extCallLoop', regexOrAST: 'AST', type: IssueTypes.L, title: 'External calls in an un-bounded `for-`loop may result in a DOS', diff --git a/src/issues/L/extCallRecipientGas.ts b/src/issues/L/extCallRecipientGas.ts index 6819d0c..f79c530 100644 --- a/src/issues/L/extCallRecipientGas.ts +++ b/src/issues/L/extCallRecipientGas.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'extCallRecipientGas', regexOrAST: 'Regex', type: IssueTypes.L, title: 'External call recipient may consume all transaction gas', diff --git a/src/issues/L/fallBackLackPayable.ts b/src/issues/L/fallBackLackPayable.ts index 26d3611..27a34c1 100644 --- a/src/issues/L/fallBackLackPayable.ts +++ b/src/issues/L/fallBackLackPayable.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'fallBackLackPayable', regexOrAST: 'Regex', type: IssueTypes.L, title: 'Fallback lacking `payable`', diff --git a/src/issues/L/frontRunnableInitializer.ts b/src/issues/L/frontRunnableInitializer.ts index ce39dcb..87adfbe 100644 --- a/src/issues/L/frontRunnableInitializer.ts +++ b/src/issues/L/frontRunnableInitializer.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'frontRunnableInitializer', regexOrAST: 'Regex', type: IssueTypes.L, title: 'Initializers could be front-run', diff --git a/src/issues/L/includeTimestampAtDeadline.ts b/src/issues/L/includeTimestampAtDeadline.ts index 6d2d631..cf2f8f4 100644 --- a/src/issues/L/includeTimestampAtDeadline.ts +++ b/src/issues/L/includeTimestampAtDeadline.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'includeTimestampAtDeadline', regexOrAST: 'Regex', type: IssueTypes.L, title: 'Signature use at deadlines should be allowed', diff --git a/src/issues/L/lackSlippage.ts b/src/issues/L/lackSlippage.ts index a2f9862..0958abf 100644 --- a/src/issues/L/lackSlippage.ts +++ b/src/issues/L/lackSlippage.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'lackSlippage', regexOrAST: 'Regex', type: IssueTypes.L, title: 'Lack of Slippage check', diff --git a/src/issues/L/mathmaxInt.ts b/src/issues/L/mathmaxInt.ts index fd16f80..f1390fd 100644 --- a/src/issues/L/mathmaxInt.ts +++ b/src/issues/L/mathmaxInt.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'mathmaxInt', regexOrAST: 'Regex', type: IssueTypes.L, title: '`Math.max(,0)` used with `int` cast to `uint`', diff --git a/src/issues/L/mintAndBurnAddress0.ts b/src/issues/L/mintAndBurnAddress0.ts index 13ee6b0..16532d7 100644 --- a/src/issues/L/mintAndBurnAddress0.ts +++ b/src/issues/L/mintAndBurnAddress0.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'mintAndBurnAddress0', regexOrAST: 'AST', type: IssueTypes.L, title: 'Prevent accidentally burning tokens', diff --git a/src/issues/L/nftOwnershipHardfork.ts b/src/issues/L/nftOwnershipHardfork.ts index b911476..d720973 100644 --- a/src/issues/L/nftOwnershipHardfork.ts +++ b/src/issues/L/nftOwnershipHardfork.ts @@ -3,6 +3,7 @@ import { ASTIssue, InputType, Instance, IssueTypes, RegexIssue } from '../../typ import { instanceFromSRC } from '../../utils'; const issue: ASTIssue = { + id: 'nftOwnershipHardfork', regexOrAST: 'AST', type: IssueTypes.L, title: 'NFT ownership doesn\'t support hard forks', diff --git a/src/issues/L/ownerRenounceDuringPause.ts b/src/issues/L/ownerRenounceDuringPause.ts index 85909d8..7cbde85 100644 --- a/src/issues/L/ownerRenounceDuringPause.ts +++ b/src/issues/L/ownerRenounceDuringPause.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'ownerRenounceDuringPause', regexOrAST: 'Regex', type: IssueTypes.L, title: 'Owner can renounce while system is paused', diff --git a/src/issues/L/possibleRounding.ts b/src/issues/L/possibleRounding.ts index db2edb0..18e36ba 100644 --- a/src/issues/L/possibleRounding.ts +++ b/src/issues/L/possibleRounding.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'possibleRounding', regexOrAST: 'Regex', type: IssueTypes.L, title: 'Possible rounding issue', diff --git a/src/issues/L/pragmaExpDeprecated.ts b/src/issues/L/pragmaExpDeprecated.ts index 1eb7b7b..00c124e 100644 --- a/src/issues/L/pragmaExpDeprecated.ts +++ b/src/issues/L/pragmaExpDeprecated.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'pragmaExpDeprecated', regexOrAST: 'Regex', type: IssueTypes.L, title: '`pragma experimental ABIEncoderV2` is deprecated', diff --git a/src/issues/L/precisionLoss.ts b/src/issues/L/precisionLoss.ts index bd4747c..8f1d569 100644 --- a/src/issues/L/precisionLoss.ts +++ b/src/issues/L/precisionLoss.ts @@ -2,6 +2,7 @@ import { IssueTypes, RegexIssue } from '../../types'; //@note there will be false positives const issue: RegexIssue = { + id: 'precisionLoss', regexOrAST: 'Regex', type: IssueTypes.L, title: 'Loss of precision', diff --git a/src/issues/L/push0Solc0820.ts b/src/issues/L/push0Solc0820.ts index 5afdace..d71c60f 100644 --- a/src/issues/L/push0Solc0820.ts +++ b/src/issues/L/push0Solc0820.ts @@ -3,6 +3,7 @@ import { findAll } from 'solidity-ast/utils'; import { instanceFromSRC } from '../../utils'; const issue: ASTIssue = { + id: 'push0Solc0820', regexOrAST: 'AST', type: IssueTypes.L, title: 'Solidity version 0.8.20+ may not work on other chains due to `PUSH0`', diff --git a/src/issues/L/safeTransferOwnership.ts b/src/issues/L/safeTransferOwnership.ts index ae90414..235f1a7 100644 --- a/src/issues/L/safeTransferOwnership.ts +++ b/src/issues/L/safeTransferOwnership.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'safeTransferOwnership', regexOrAST: 'Regex', type: IssueTypes.L, title: 'Use `Ownable2Step.transferOwnership` instead of `Ownable.transferOwnership`', diff --git a/src/issues/L/solc1314OptimizerBug.ts b/src/issues/L/solc1314OptimizerBug.ts index 2b5ebd0..e029940 100644 --- a/src/issues/L/solc1314OptimizerBug.ts +++ b/src/issues/L/solc1314OptimizerBug.ts @@ -3,6 +3,7 @@ import { findAll } from 'solidity-ast/utils'; import { instanceFromSRC } from '../../utils'; const issue: ASTIssue = { + id: 'solc1314OptimizerBug', regexOrAST: 'AST', type: IssueTypes.L, title: 'File allows a version of solidity that is susceptible to an assembly optimizer bug', diff --git a/src/issues/L/sweepingRescuing.ts b/src/issues/L/sweepingRescuing.ts index 6e47f2f..68ef690 100644 --- a/src/issues/L/sweepingRescuing.ts +++ b/src/issues/L/sweepingRescuing.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'sweepingRescuing', regexOrAST: 'Regex', type: IssueTypes.L, title: 'Sweeping may break accounting if tokens with multiple addresses are used', diff --git a/src/issues/L/symbolNotERC20.ts b/src/issues/L/symbolNotERC20.ts index 18aad60..cd63081 100644 --- a/src/issues/L/symbolNotERC20.ts +++ b/src/issues/L/symbolNotERC20.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'symbolNotERC20', regexOrAST: 'Regex', type: IssueTypes.L, title: '`symbol()` is not a part of the ERC-20 standard', diff --git a/src/issues/L/unsafeCasting.ts b/src/issues/L/unsafeCasting.ts index b082f63..3ae18fb 100644 --- a/src/issues/L/unsafeCasting.ts +++ b/src/issues/L/unsafeCasting.ts @@ -5,6 +5,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'unsafeCasting', regexOrAST: 'AST', type: IssueTypes.L, title: diff --git a/src/issues/L/unsafeERC20Operations.ts b/src/issues/L/unsafeERC20Operations.ts index 0f241d2..c78d280 100644 --- a/src/issues/L/unsafeERC20Operations.ts +++ b/src/issues/L/unsafeERC20Operations.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'unsafeERC20Operations', regexOrAST: 'Regex', type: IssueTypes.L, title: 'Unsafe ERC20 operation(s)', diff --git a/src/issues/L/unsafeReturnBomb.ts b/src/issues/L/unsafeReturnBomb.ts index 66b513f..29a76f0 100644 --- a/src/issues/L/unsafeReturnBomb.ts +++ b/src/issues/L/unsafeReturnBomb.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'unsafeReturnBomb', regexOrAST: 'Regex', type: IssueTypes.L, title: 'Unsafe solidity low-level call can cause gas grief attack', diff --git a/src/issues/L/unspecifiedPragma.ts b/src/issues/L/unspecifiedPragma.ts index a653699..dc81e49 100644 --- a/src/issues/L/unspecifiedPragma.ts +++ b/src/issues/L/unspecifiedPragma.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'unspecifiedPragma', regexOrAST: 'Regex', type: IssueTypes.L, title: 'Unspecific compiler version pragma', diff --git a/src/issues/L/upgradeableMissingGap.ts b/src/issues/L/upgradeableMissingGap.ts index 9a770f9..a5f6587 100644 --- a/src/issues/L/upgradeableMissingGap.ts +++ b/src/issues/L/upgradeableMissingGap.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'upgradeableMissingGap', regexOrAST: 'Regex', type: IssueTypes.L, title: diff --git a/src/issues/L/upgradeableNotInit.ts b/src/issues/L/upgradeableNotInit.ts index b626617..6aab8b1 100644 --- a/src/issues/L/upgradeableNotInit.ts +++ b/src/issues/L/upgradeableNotInit.ts @@ -2,6 +2,7 @@ import { IssueTypes, RegexIssue } from '../../types'; //@audit-issue TODO - lots of false positives const issue: RegexIssue = { + id: 'upgradeableNotInit', regexOrAST: 'Regex', type: IssueTypes.L, title: 'Upgradeable contract not initialized', diff --git a/src/issues/L/useOfEcrecover.ts b/src/issues/L/useOfEcrecover.ts index c871808..e737e54 100644 --- a/src/issues/L/useOfEcrecover.ts +++ b/src/issues/L/useOfEcrecover.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'useOfEcrecover', regexOrAST: 'Regex', type: IssueTypes.L, title: "Use of ecrecover is susceptible to signature malleability", diff --git a/src/issues/L/useOnlyInitializing.ts b/src/issues/L/useOnlyInitializing.ts index e844413..9d47bc1 100644 --- a/src/issues/L/useOnlyInitializing.ts +++ b/src/issues/L/useOnlyInitializing.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'useOnlyInitializing', regexOrAST: 'AST', type: IssueTypes.L, title: 'Use `initializer` for public-facing functions only. Replace with `onlyInitializing` on internal functions.', diff --git a/src/issues/L/year365.ts b/src/issues/L/year365.ts index 21d47e0..c26db78 100644 --- a/src/issues/L/year365.ts +++ b/src/issues/L/year365.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'year365', regexOrAST: 'Regex', type: IssueTypes.L, title: 'A year is not always 365 days', diff --git a/src/issues/M/FoTTokens.ts b/src/issues/M/FoTTokens.ts index 1dad0d2..1555c92 100644 --- a/src/issues/M/FoTTokens.ts +++ b/src/issues/M/FoTTokens.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'foTTokens', regexOrAST: 'AST', type: IssueTypes.M, title: 'Contracts are vulnerable to fee-on-transfer accounting-related issues', diff --git a/src/issues/M/NFTRedefinesMint.ts b/src/issues/M/NFTRedefinesMint.ts index 47c0c19..3c2c796 100644 --- a/src/issues/M/NFTRedefinesMint.ts +++ b/src/issues/M/NFTRedefinesMint.ts @@ -4,6 +4,7 @@ import { ASTIssue, InputType, Instance, IssueTypes, RegexIssue } from '../../typ import { instanceFromSRC, topLevelFiles, getStorageVariable } from '../../utils'; const issue: ASTIssue = { + id: 'nftRedefinesMint', regexOrAST: 'AST', type: IssueTypes.L, title: "NFT contract redefines `_mint()`/`_safeMint()`, but not both", diff --git a/src/issues/M/approve0first.ts b/src/issues/M/approve0first.ts index 6df546d..193a906 100644 --- a/src/issues/M/approve0first.ts +++ b/src/issues/M/approve0first.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'approve0first', regexOrAST: 'Regex', type: IssueTypes.L, title: "`approve()`/`safeApprove()` may revert if the current approval is not zero", diff --git a/src/issues/M/avoidTx.origin.ts b/src/issues/M/avoidTx.origin.ts index dc03020..b281111 100644 --- a/src/issues/M/avoidTx.origin.ts +++ b/src/issues/M/avoidTx.origin.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'avoidTxOrigin', regexOrAST: 'Regex', type: IssueTypes.L, title: 'Use of `tx.origin` is unsafe in almost every context', diff --git a/src/issues/M/blockNumberL2.ts b/src/issues/M/blockNumberL2.ts index a19103d..5f01279 100644 --- a/src/issues/M/blockNumberL2.ts +++ b/src/issues/M/blockNumberL2.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'blockNumberL2', regexOrAST: 'Regex', type: IssueTypes.M, title: diff --git a/src/issues/M/centralizationRisk.ts b/src/issues/M/centralizationRisk.ts index 26071a6..773862d 100644 --- a/src/issues/M/centralizationRisk.ts +++ b/src/issues/M/centralizationRisk.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'centralizationRisk', regexOrAST: 'Regex', type: IssueTypes.M, title: 'Centralization Risk for trusted owners', diff --git a/src/issues/M/deprecatedChainlinkFunction.ts b/src/issues/M/deprecatedChainlinkFunction.ts index 92aaefc..b446c34 100644 --- a/src/issues/M/deprecatedChainlinkFunction.ts +++ b/src/issues/M/deprecatedChainlinkFunction.ts @@ -1,6 +1,7 @@ import {IssueTypes} from "../../types"; const issue = { + id: 'deprecatedChainlinkFunction', regexOrAST: 'Regex', type: IssueTypes.M, title: 'Use of deprecated chainlink function: `latestAnswer()`', diff --git a/src/issues/M/deprecatedTransfer.ts b/src/issues/M/deprecatedTransfer.ts index 4219157..1802905 100644 --- a/src/issues/M/deprecatedTransfer.ts +++ b/src/issues/M/deprecatedTransfer.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'deprecatedTransfer', regexOrAST: 'AST', type: IssueTypes.M, title: '`call()` should be used instead of `transfer()` on an `address payable`', diff --git a/src/issues/M/erc721safeMint.ts b/src/issues/M/erc721safeMint.ts index 39ec7c0..560ce6e 100644 --- a/src/issues/M/erc721safeMint.ts +++ b/src/issues/M/erc721safeMint.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'erc721safeMint', regexOrAST: 'Regex', type: IssueTypes.M, title: '`_safeMint()` should be used rather than `_mint()` wherever possible', diff --git a/src/issues/M/erc721safeTransferFrom.ts b/src/issues/M/erc721safeTransferFrom.ts index 76f221d..3de57eb 100644 --- a/src/issues/M/erc721safeTransferFrom.ts +++ b/src/issues/M/erc721safeTransferFrom.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'erc721safeTransferFrom', regexOrAST: 'Regex', type: IssueTypes.M, title: 'Using `transferFrom` on ERC721 tokens', diff --git a/src/issues/M/feeOver100.ts b/src/issues/M/feeOver100.ts index 23d346f..d66c5ad 100644 --- a/src/issues/M/feeOver100.ts +++ b/src/issues/M/feeOver100.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'feeOver100', regexOrAST: 'AST', type: IssueTypes.M, title: 'Fees can be set to be greater than 100%.', diff --git a/src/issues/M/increaseAllowanceUSDT.ts b/src/issues/M/increaseAllowanceUSDT.ts index f4b4eab..0dda6d1 100644 --- a/src/issues/M/increaseAllowanceUSDT.ts +++ b/src/issues/M/increaseAllowanceUSDT.ts @@ -4,6 +4,7 @@ import { ASTIssue, InputType, Instance, IssueTypes, RegexIssue } from '../../typ import { instanceFromSRC, topLevelFiles, getStorageVariable } from '../../utils'; const issue: RegexIssue = { + id: 'increaseAllowanceUSDT', regexOrAST: 'Regex', type: IssueTypes.M, title: "`increaseAllowance/decreaseAllowance` won't work on mainnet for USDT", diff --git a/src/issues/M/keccakOnStructOrArray.ts b/src/issues/M/keccakOnStructOrArray.ts index ad44cc8..78cd8a1 100644 --- a/src/issues/M/keccakOnStructOrArray.ts +++ b/src/issues/M/keccakOnStructOrArray.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'keccakOnStructOrArray', regexOrAST: 'AST', type: IssueTypes.M, title: 'Lack of EIP-712 compliance: using `keccak256()` directly on an array or struct variable', diff --git a/src/issues/M/libraryPublicFunction.ts b/src/issues/M/libraryPublicFunction.ts index f39ff52..50f41ce 100644 --- a/src/issues/M/libraryPublicFunction.ts +++ b/src/issues/M/libraryPublicFunction.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'libraryPublicFunction', regexOrAST: 'AST', type: IssueTypes.M, title: 'Library function isn\'t `internal` or `private`', diff --git a/src/issues/M/soladySafeTransferLib.ts b/src/issues/M/soladySafeTransferLib.ts index dbedc4b..4a7360c 100644 --- a/src/issues/M/soladySafeTransferLib.ts +++ b/src/issues/M/soladySafeTransferLib.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'soladySafeTransferLib', regexOrAST: 'Regex', type: IssueTypes.M, title: diff --git a/src/issues/M/solmateSafeTransferLib.ts b/src/issues/M/solmateSafeTransferLib.ts index b951276..5ee5977 100644 --- a/src/issues/M/solmateSafeTransferLib.ts +++ b/src/issues/M/solmateSafeTransferLib.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'solmateSafeTransferLib', regexOrAST: 'Regex', type: IssueTypes.M, title: diff --git a/src/issues/M/staleOracleData.ts b/src/issues/M/staleOracleData.ts index 8e9a144..06da01d 100644 --- a/src/issues/M/staleOracleData.ts +++ b/src/issues/M/staleOracleData.ts @@ -3,6 +3,7 @@ import { ASTIssue, InputType, Instance, IssueTypes, RegexIssue } from '../../typ import { instanceFromSRC, lineFromIndex } from '../../utils'; const issue: ASTIssue = { + id: 'staleOracleData', regexOrAST: 'AST', type: IssueTypes.M, title: "Chainlink's `latestRoundData` might return stale or incorrect results", diff --git a/src/issues/M/staleOracleDataL2Sequencer.ts b/src/issues/M/staleOracleDataL2Sequencer.ts index 0522ad3..c0ff2de 100644 --- a/src/issues/M/staleOracleDataL2Sequencer.ts +++ b/src/issues/M/staleOracleDataL2Sequencer.ts @@ -3,6 +3,7 @@ import { ASTIssue, InputType, Instance, IssueTypes, RegexIssue } from '../../typ import { instanceFromSRC, lineFromIndex } from '../../utils'; const issue: ASTIssue = { + id: 'staleOracleDataL2Sequencer', regexOrAST: 'AST', type: IssueTypes.M, title: "Missing checks for whether the L2 Sequencer is active", diff --git a/src/issues/M/supportInterface.ts b/src/issues/M/supportInterface.ts index 8b7809c..c69a04e 100644 --- a/src/issues/M/supportInterface.ts +++ b/src/issues/M/supportInterface.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'supportInterface', regexOrAST: 'Regex', type: IssueTypes.M, title: 'Direct `supportsInterface()` calls may cause caller to revert', diff --git a/src/issues/M/uncheckedERC20Transfer.ts b/src/issues/M/uncheckedERC20Transfer.ts index db64a0b..c708ad5 100644 --- a/src/issues/M/uncheckedERC20Transfer.ts +++ b/src/issues/M/uncheckedERC20Transfer.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'uncheckedERC20Transfer', regexOrAST: 'AST', type: IssueTypes.M, title: 'Return values of `transfer()`/`transferFrom()` not checked', diff --git a/src/issues/M/unsafeERC20Transfer.ts b/src/issues/M/unsafeERC20Transfer.ts index d04bfac..b7afd08 100644 --- a/src/issues/M/unsafeERC20Transfer.ts +++ b/src/issues/M/unsafeERC20Transfer.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'unsafeERC20Transfer', regexOrAST: 'AST', type: IssueTypes.M, title: 'Unsafe use of `transfer()`/`transferFrom()` with `IERC20`', diff --git a/src/issues/NC/abiEncodeCall.ts b/src/issues/NC/abiEncodeCall.ts index 26fea38..63ba732 100644 --- a/src/issues/NC/abiEncodeCall.ts +++ b/src/issues/NC/abiEncodeCall.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'abiEncodeCall', regexOrAST: 'Regex', type: IssueTypes.NC, title: diff --git a/src/issues/NC/abicoderv2.ts b/src/issues/NC/abicoderv2.ts index 2734ef9..24c8af9 100644 --- a/src/issues/NC/abicoderv2.ts +++ b/src/issues/NC/abicoderv2.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'abicoderV2', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'abicoder v2 is enabled by default', diff --git a/src/issues/NC/address0Check.ts b/src/issues/NC/address0Check.ts index 187a76f..65b5ad0 100644 --- a/src/issues/NC/address0Check.ts +++ b/src/issues/NC/address0Check.ts @@ -3,6 +3,7 @@ import { ASTIssue, InputType, Instance, IssueTypes, RegexIssue } from '../../typ import { getStorageVariable, instanceFromSRC } from '../../utils'; const issue: ASTIssue = { + id: 'address0Check', regexOrAST: 'AST', type: IssueTypes.NC, title: 'Missing checks for `address(0)` when assigning values to address state variables', diff --git a/src/issues/NC/arrayIndices.ts b/src/issues/NC/arrayIndices.ts index 9da2eee..59bfd3f 100644 --- a/src/issues/NC/arrayIndices.ts +++ b/src/issues/NC/arrayIndices.ts @@ -3,6 +3,7 @@ import { ASTIssue, InputType, Instance, IssueTypes, RegexIssue } from '../../typ import { getStorageVariable, instanceFromSRC } from '../../utils'; const issue: ASTIssue = { + id: 'arrayIndices', regexOrAST: 'AST', type: IssueTypes.NC, title: 'Array indices should be referenced via `enum`s rather than via numeric literals', diff --git a/src/issues/NC/assertRequire.ts b/src/issues/NC/assertRequire.ts index 4d33b96..45bdba2 100644 --- a/src/issues/NC/assertRequire.ts +++ b/src/issues/NC/assertRequire.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'assertRequire', regexOrAST: 'Regex', type: IssueTypes.NC, title: '`require()` should be used instead of `assert()`', diff --git a/src/issues/NC/concat.ts b/src/issues/NC/concat.ts index f0d0735..7dc304c 100644 --- a/src/issues/NC/concat.ts +++ b/src/issues/NC/concat.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'concat', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'Use `string.concat()` or `bytes.concat()` instead of `abi.encodePacked`', diff --git a/src/issues/NC/constantStyle.ts b/src/issues/NC/constantStyle.ts index 0a3bc51..dc83b75 100644 --- a/src/issues/NC/constantStyle.ts +++ b/src/issues/NC/constantStyle.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'constantStyle', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'Constants should be in CONSTANT_CASE', diff --git a/src/issues/NC/constantsInsteadMagic.ts b/src/issues/NC/constantsInsteadMagic.ts index 8eea778..a6b0d92 100644 --- a/src/issues/NC/constantsInsteadMagic.ts +++ b/src/issues/NC/constantsInsteadMagic.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'constantsInsteadMagic', regexOrAST: 'Regex', type: IssueTypes.NC, title: '`constant`s should be defined rather than using magic numbers', diff --git a/src/issues/NC/controlStructureStyle.ts b/src/issues/NC/controlStructureStyle.ts index 638d136..dececc6 100644 --- a/src/issues/NC/controlStructureStyle.ts +++ b/src/issues/NC/controlStructureStyle.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'controlStructureStyle', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'Control structures do not follow the Solidity Style Guide', diff --git a/src/issues/NC/criticalChange.ts b/src/issues/NC/criticalChange.ts index 071d3d3..1c67011 100644 --- a/src/issues/NC/criticalChange.ts +++ b/src/issues/NC/criticalChange.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'criticalChange', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'Critical Changes Should Use Two-step Procedure', diff --git a/src/issues/NC/dangerWhileTrue.ts b/src/issues/NC/dangerWhileTrue.ts index 511a91a..d828447 100644 --- a/src/issues/NC/dangerWhileTrue.ts +++ b/src/issues/NC/dangerWhileTrue.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'dangerWhileTrue', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'Dangerous `while(true)` loop', diff --git a/src/issues/NC/defaultVisibility.ts b/src/issues/NC/defaultVisibility.ts index 481d4dc..0c6b5b7 100644 --- a/src/issues/NC/defaultVisibility.ts +++ b/src/issues/NC/defaultVisibility.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'defaultVisibility', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'Default Visibility for constants', diff --git a/src/issues/NC/deleteLogs.ts b/src/issues/NC/deleteLogs.ts index 81060c7..2e15545 100644 --- a/src/issues/NC/deleteLogs.ts +++ b/src/issues/NC/deleteLogs.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'deleteLogs', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'Delete rogue `console.log` imports', diff --git a/src/issues/NC/disableRenounceOwnership.ts b/src/issues/NC/disableRenounceOwnership.ts index 13d8fde..9b68d65 100644 --- a/src/issues/NC/disableRenounceOwnership.ts +++ b/src/issues/NC/disableRenounceOwnership.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'disableRenounceOwnership', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'Consider disabling `renounceOwnership()`', diff --git a/src/issues/NC/draft-OZ.ts b/src/issues/NC/draft-OZ.ts index 342427f..d667e6b 100644 --- a/src/issues/NC/draft-OZ.ts +++ b/src/issues/NC/draft-OZ.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'draftOZ', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'Draft Dependencies', diff --git a/src/issues/NC/duplicateRequireRevert.ts b/src/issues/NC/duplicateRequireRevert.ts index 15958a7..ed11a0f 100644 --- a/src/issues/NC/duplicateRequireRevert.ts +++ b/src/issues/NC/duplicateRequireRevert.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'duplicateRequireRevert', regexOrAST: 'AST', type: IssueTypes.NC, title: 'Duplicated `require()`/`revert()` Checks Should Be Refactored To A Modifier Or Function', diff --git a/src/issues/NC/elseBlockOnReturn.ts b/src/issues/NC/elseBlockOnReturn.ts index d3de8dd..b7fa163 100644 --- a/src/issues/NC/elseBlockOnReturn.ts +++ b/src/issues/NC/elseBlockOnReturn.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'elseBlockOnReturn', regexOrAST: 'AST', type: IssueTypes.NC, title: '`else`-block not required', diff --git a/src/issues/NC/errorneverUsed.ts b/src/issues/NC/errorneverUsed.ts index aac7428..efad2a5 100644 --- a/src/issues/NC/errorneverUsed.ts +++ b/src/issues/NC/errorneverUsed.ts @@ -4,6 +4,7 @@ import { instanceFromSRC, lineFromIndex } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'errorneverUsed', regexOrAST: 'AST', type: IssueTypes.NC, title: 'Unused `error` definition', diff --git a/src/issues/NC/eventNeverEmitted.ts b/src/issues/NC/eventNeverEmitted.ts index 289c131..c58ef89 100644 --- a/src/issues/NC/eventNeverEmitted.ts +++ b/src/issues/NC/eventNeverEmitted.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'eventNeverEmitted', regexOrAST: 'AST', type: IssueTypes.NC, title: 'Event is never emitted', diff --git a/src/issues/NC/eventNoArgs.ts b/src/issues/NC/eventNoArgs.ts index fa41381..cde68a1 100644 --- a/src/issues/NC/eventNoArgs.ts +++ b/src/issues/NC/eventNoArgs.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'eventNoArgs', regexOrAST: 'AST', type: IssueTypes.NC, title: 'Events should use parameters to convey information', diff --git a/src/issues/NC/eventNotProperlyIndexed.ts b/src/issues/NC/eventNotProperlyIndexed.ts index 8b10cd4..30f098c 100644 --- a/src/issues/NC/eventNotProperlyIndexed.ts +++ b/src/issues/NC/eventNotProperlyIndexed.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'eventNotProperlyIndexed', regexOrAST: 'AST', type: IssueTypes.NC, title: 'Event missing indexed field', diff --git a/src/issues/NC/eventOldNew.ts b/src/issues/NC/eventOldNew.ts index 40df323..7ad6da5 100644 --- a/src/issues/NC/eventOldNew.ts +++ b/src/issues/NC/eventOldNew.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'eventOldNew', regexOrAST: 'AST', type: IssueTypes.NC, title: 'Events that mark critical parameter changes should contain both the old and the new value', diff --git a/src/issues/NC/functionOrdering.ts b/src/issues/NC/functionOrdering.ts index 81a46e7..90b035b 100644 --- a/src/issues/NC/functionOrdering.ts +++ b/src/issues/NC/functionOrdering.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'functionOrdering', regexOrAST: 'AST', type: IssueTypes.NC, title: 'Function ordering does not follow the Solidity style guide', diff --git a/src/issues/NC/functionsTooLong.ts b/src/issues/NC/functionsTooLong.ts index d64080b..b65e93c 100644 --- a/src/issues/NC/functionsTooLong.ts +++ b/src/issues/NC/functionsTooLong.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'functionsTooLong', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'Functions should not be longer than 50 lines', diff --git a/src/issues/NC/implicitInt.ts b/src/issues/NC/implicitInt.ts index 1a8cc33..449b1e4 100644 --- a/src/issues/NC/implicitInt.ts +++ b/src/issues/NC/implicitInt.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'implicitInt', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'Change int to int256', diff --git a/src/issues/NC/implicitUint.ts b/src/issues/NC/implicitUint.ts index 671f4f8..863cf35 100644 --- a/src/issues/NC/implicitUint.ts +++ b/src/issues/NC/implicitUint.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'implicitUint', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'Change uint to uint256', diff --git a/src/issues/NC/interfaceInaming.ts b/src/issues/NC/interfaceInaming.ts index 0e380d4..55ccb6b 100644 --- a/src/issues/NC/interfaceInaming.ts +++ b/src/issues/NC/interfaceInaming.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'interfaceInaming', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'Interfaces should be indicated with an `I` prefix in the contract name', diff --git a/src/issues/NC/interfaceOwnFile.ts b/src/issues/NC/interfaceOwnFile.ts index cdddd8a..97262ed 100644 --- a/src/issues/NC/interfaceOwnFile.ts +++ b/src/issues/NC/interfaceOwnFile.ts @@ -3,6 +3,7 @@ import { findAll } from 'solidity-ast/utils'; import { instanceFromSRC } from '../../utils'; const issue: ASTIssue = { + id: 'interfaceOwnFile', regexOrAST: 'AST', type: IssueTypes.NC, title: 'Interfaces should be defined in separate files from their usage', diff --git a/src/issues/NC/lackReasonableBounds.ts b/src/issues/NC/lackReasonableBounds.ts index da1b344..e1d4a14 100644 --- a/src/issues/NC/lackReasonableBounds.ts +++ b/src/issues/NC/lackReasonableBounds.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'lackReasonableBounds', regexOrAST: 'AST', type: IssueTypes.NC, title: 'Lack of checks in setters', diff --git a/src/issues/NC/linesTooLong.ts b/src/issues/NC/linesTooLong.ts index 6e87248..826e4f0 100644 --- a/src/issues/NC/linesTooLong.ts +++ b/src/issues/NC/linesTooLong.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'linesTooLong', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'Lines are too long', diff --git a/src/issues/NC/mappingStyle.ts b/src/issues/NC/mappingStyle.ts index 502f500..202169c 100644 --- a/src/issues/NC/mappingStyle.ts +++ b/src/issues/NC/mappingStyle.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'mappingStyle', regexOrAST: 'Regex', type: IssueTypes.NC, title: '`mapping` definitions do not follow the Solidity Style Guide', diff --git a/src/issues/NC/maxUint.ts b/src/issues/NC/maxUint.ts index 0d2d4a1..1262825 100644 --- a/src/issues/NC/maxUint.ts +++ b/src/issues/NC/maxUint.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'maxUint', regexOrAST: 'Regex', type: IssueTypes.NC, title: '`type(uint).max` should be used instead of `uint(-1)`', diff --git a/src/issues/NC/maxUint256.ts b/src/issues/NC/maxUint256.ts index dbbbc78..91914ce 100644 --- a/src/issues/NC/maxUint256.ts +++ b/src/issues/NC/maxUint256.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'maxUint256', regexOrAST: 'Regex', type: IssueTypes.NC, title: '`type(uint256).max` should be used instead of `2 ** 256 - 1`', diff --git a/src/issues/NC/missingEventSetters.ts b/src/issues/NC/missingEventSetters.ts index a3fed1d..07f9d4c 100644 --- a/src/issues/NC/missingEventSetters.ts +++ b/src/issues/NC/missingEventSetters.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'missingEventSetters', regexOrAST: 'AST', type: IssueTypes.NC, title: 'Missing Event for critical parameters change', diff --git a/src/issues/NC/missingNatspec.ts b/src/issues/NC/missingNatspec.ts index 7287db6..03d9994 100644 --- a/src/issues/NC/missingNatspec.ts +++ b/src/issues/NC/missingNatspec.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'missingNatspec', regexOrAST: 'AST', type: IssueTypes.NC, title: 'NatSpec is completely non-existent on functions that should have them', diff --git a/src/issues/NC/missingNatspecParam.ts b/src/issues/NC/missingNatspecParam.ts index 8fa4fcc..6eb654a 100644 --- a/src/issues/NC/missingNatspecParam.ts +++ b/src/issues/NC/missingNatspecParam.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'missingNatspecParam', regexOrAST: 'AST', type: IssueTypes.NC, title: 'Incomplete NatSpec: `@param` is missing on actually documented functions', diff --git a/src/issues/NC/missingNatspecReturn.ts b/src/issues/NC/missingNatspecReturn.ts index 91d0152..13e7303 100644 --- a/src/issues/NC/missingNatspecReturn.ts +++ b/src/issues/NC/missingNatspecReturn.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'missingNatspecReturn', regexOrAST: 'AST', type: IssueTypes.NC, title: 'Incomplete NatSpec: `@return` is missing on actually documented functions', diff --git a/src/issues/NC/missingSPDX.ts b/src/issues/NC/missingSPDX.ts index 8bc91e6..670a404 100644 --- a/src/issues/NC/missingSPDX.ts +++ b/src/issues/NC/missingSPDX.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'missingSPDX', regexOrAST: 'AST', type: IssueTypes.NC, title: 'File\'s first line is not an SPDX Identifier', diff --git a/src/issues/NC/modifierForMsgSender.ts b/src/issues/NC/modifierForMsgSender.ts index d30e471..1fec9af 100644 --- a/src/issues/NC/modifierForMsgSender.ts +++ b/src/issues/NC/modifierForMsgSender.ts @@ -2,6 +2,7 @@ import { IssueTypes, RegexIssue } from '../../types'; // Also catches the checks in modifiers and should be an AST detector const issue: RegexIssue = { + id: 'modifierForMsgSender', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'Use a `modifier` instead of a `require/if` statement for a special `msg.sender` actor', diff --git a/src/issues/NC/multipleConstantDeclaration.ts b/src/issues/NC/multipleConstantDeclaration.ts index cf4aff3..34cce8e 100644 --- a/src/issues/NC/multipleConstantDeclaration.ts +++ b/src/issues/NC/multipleConstantDeclaration.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'multipleConstantDeclaration', regexOrAST: 'AST', type: IssueTypes.NC, title: 'Constant state variables defined more than once', diff --git a/src/issues/NC/namedMappings.ts b/src/issues/NC/namedMappings.ts index db3ea3b..96e4fcc 100644 --- a/src/issues/NC/namedMappings.ts +++ b/src/issues/NC/namedMappings.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'namedMappings', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'Consider using named mappings', diff --git a/src/issues/NC/noAddressHardcode.ts b/src/issues/NC/noAddressHardcode.ts index 07e165c..41679d7 100644 --- a/src/issues/NC/noAddressHardcode.ts +++ b/src/issues/NC/noAddressHardcode.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'noAddressHardcode', regexOrAST: 'Regex', type: IssueTypes.NC, title: '`address`s shouldn\'t be hard-coded', diff --git a/src/issues/NC/nonReentrantBeforeModifiers.ts b/src/issues/NC/nonReentrantBeforeModifiers.ts index 0a47d49..bc11173 100644 --- a/src/issues/NC/nonReentrantBeforeModifiers.ts +++ b/src/issues/NC/nonReentrantBeforeModifiers.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'nonReentrantBeforeModifiers', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'The `nonReentrant` `modifier` should occur before all other modifiers', diff --git a/src/issues/NC/numericTimeDays.ts b/src/issues/NC/numericTimeDays.ts index a6d30ca..c557ffd 100644 --- a/src/issues/NC/numericTimeDays.ts +++ b/src/issues/NC/numericTimeDays.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'numericTimeDays', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'Numeric values having to do with time should use time units for readability', diff --git a/src/issues/NC/onlyConstantsInUppercase.ts b/src/issues/NC/onlyConstantsInUppercase.ts index d66b92b..cb16471 100644 --- a/src/issues/NC/onlyConstantsInUppercase.ts +++ b/src/issues/NC/onlyConstantsInUppercase.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'onlyConstantsInUppercase', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'Variable names that consist of all capital letters should be reserved for `constant`/`immutable` variables', diff --git a/src/issues/NC/ownerCanRenounceWhilePaused.ts b/src/issues/NC/ownerCanRenounceWhilePaused.ts index d1a5aa6..a1047a2 100644 --- a/src/issues/NC/ownerCanRenounceWhilePaused.ts +++ b/src/issues/NC/ownerCanRenounceWhilePaused.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'ownerCanRenounceWhilePaused', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'Owner can renounce while system is paused', diff --git a/src/issues/NC/redundantNamedReturn.ts b/src/issues/NC/redundantNamedReturn.ts index fd7534c..bcee59f 100644 --- a/src/issues/NC/redundantNamedReturn.ts +++ b/src/issues/NC/redundantNamedReturn.ts @@ -5,6 +5,7 @@ import { instanceFromSRC } from '../../utils'; //@note trop fier de moi const issue: ASTIssue = { + id: 'redundantNamedReturn', regexOrAST: 'AST', type: IssueTypes.NC, title: 'Adding a `return` statement when the function defines a named return variable, is redundant', diff --git a/src/issues/NC/requireWithString.ts b/src/issues/NC/requireWithString.ts index 5a5c795..43d962a 100644 --- a/src/issues/NC/requireWithString.ts +++ b/src/issues/NC/requireWithString.ts @@ -3,6 +3,7 @@ import { ASTIssue, InputType, Instance, IssueTypes, RegexIssue } from '../../typ import { instanceFromSRC } from '../../utils'; const issue: ASTIssue = { + id: 'requireWithString', regexOrAST: 'AST', type: IssueTypes.NC, title: '`require()` / `revert()` statements should have descriptive reason strings', diff --git a/src/issues/NC/revertWithoutArgument.ts b/src/issues/NC/revertWithoutArgument.ts index c86738c..6175074 100644 --- a/src/issues/NC/revertWithoutArgument.ts +++ b/src/issues/NC/revertWithoutArgument.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'revertWithoutArgument', regexOrAST: 'Regex', type: IssueTypes.NC, title: "Take advantage of Custom Error's return value property", diff --git a/src/issues/NC/safeMath08.ts b/src/issues/NC/safeMath08.ts index 7eb1228..addff7d 100644 --- a/src/issues/NC/safeMath08.ts +++ b/src/issues/NC/safeMath08.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'safeMath08', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'Deprecated library used for Solidity `>= 0.8` : SafeMath', diff --git a/src/issues/NC/scientificNotationExponent.ts b/src/issues/NC/scientificNotationExponent.ts index 7d2bfdf..2d1f45a 100644 --- a/src/issues/NC/scientificNotationExponent.ts +++ b/src/issues/NC/scientificNotationExponent.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'scientificNotationExponent', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'Use scientific notation (e.g. `1e18`) rather than exponentiation (e.g. `10**18`)', diff --git a/src/issues/NC/scientificNotationZeros.ts b/src/issues/NC/scientificNotationZeros.ts index 9b3e97c..2db53ed 100644 --- a/src/issues/NC/scientificNotationZeros.ts +++ b/src/issues/NC/scientificNotationZeros.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'scientificNotationZeros', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'Use scientific notation for readability reasons for large multiples of ten', diff --git a/src/issues/NC/sensitiveTerms.ts b/src/issues/NC/sensitiveTerms.ts index 75495b5..fde1037 100644 --- a/src/issues/NC/sensitiveTerms.ts +++ b/src/issues/NC/sensitiveTerms.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'sensitiveTerms', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'Avoid the use of sensitive terms', diff --git a/src/issues/NC/stringQuote.ts b/src/issues/NC/stringQuote.ts index 6b233d5..896eefd 100644 --- a/src/issues/NC/stringQuote.ts +++ b/src/issues/NC/stringQuote.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'stringQuote', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'Strings should use double quotes rather than single quotes', diff --git a/src/issues/NC/style.ts b/src/issues/NC/style.ts index 6e49610..0356e46 100644 --- a/src/issues/NC/style.ts +++ b/src/issues/NC/style.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'style', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'Function writing that does not comply with the Solidity Style Guide', diff --git a/src/issues/NC/styleGuide.ts b/src/issues/NC/styleGuide.ts index 7d060b6..96874d6 100644 --- a/src/issues/NC/styleGuide.ts +++ b/src/issues/NC/styleGuide.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'styleGuide', regexOrAST: 'AST', type: IssueTypes.NC, title: "Contract does not follow the Solidity style guide's suggested layout ordering", diff --git a/src/issues/NC/todoLeftInTheCode.ts b/src/issues/NC/todoLeftInTheCode.ts index e72ae96..88ff253 100644 --- a/src/issues/NC/todoLeftInTheCode.ts +++ b/src/issues/NC/todoLeftInTheCode.ts @@ -3,6 +3,7 @@ import { IssueTypes, RegexIssue } from '../../types'; // TODO: This finding won't work until we add a flag to specify findings // that either also search in commentsOr only search in comments const issue: RegexIssue = { + id: 'todoLeftInTheCode', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'TODO Left in the code', diff --git a/src/issues/NC/unclearRequire.ts b/src/issues/NC/unclearRequire.ts index cebb67b..1947c10 100644 --- a/src/issues/NC/unclearRequire.ts +++ b/src/issues/NC/unclearRequire.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'unclearRequire', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'Some require descriptions are not clear', diff --git a/src/issues/NC/underscoreDecimals.ts b/src/issues/NC/underscoreDecimals.ts index e1e01ab..213fdf7 100644 --- a/src/issues/NC/underscoreDecimals.ts +++ b/src/issues/NC/underscoreDecimals.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'underscoreDecimals', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'Use Underscores for Number Literals (add an underscore every 3 digits)', diff --git a/src/issues/NC/underscoreInternal.ts b/src/issues/NC/underscoreInternal.ts index a2a4243..c5e20e7 100644 --- a/src/issues/NC/underscoreInternal.ts +++ b/src/issues/NC/underscoreInternal.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'underscoreInternal', regexOrAST: 'AST', type: IssueTypes.NC, title: 'Internal and private variables and functions names should begin with an underscore', diff --git a/src/issues/NC/unindexedEvent.ts b/src/issues/NC/unindexedEvent.ts index 01f1799..90d4db3 100644 --- a/src/issues/NC/unindexedEvent.ts +++ b/src/issues/NC/unindexedEvent.ts @@ -4,6 +4,7 @@ import util from 'util'; import { instanceFromSRC } from '../../utils'; const issue: ASTIssue = { + id: 'unindexedEvent', regexOrAST: 'AST', type: IssueTypes.NC, title: 'Event is missing `indexed` fields', diff --git a/src/issues/NC/useConstants.ts b/src/issues/NC/useConstants.ts index 4b31a57..d458230 100644 --- a/src/issues/NC/useConstants.ts +++ b/src/issues/NC/useConstants.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'useConstants', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'Constants should be defined rather than using magic numbers', diff --git a/src/issues/NC/uselessPublic.ts b/src/issues/NC/uselessPublic.ts index 7156da3..c5df7e2 100644 --- a/src/issues/NC/uselessPublic.ts +++ b/src/issues/NC/uselessPublic.ts @@ -4,6 +4,7 @@ import { instanceFromSRC } from '../../utils'; import util from 'util'; const issue: ASTIssue = { + id: 'uselessPublic', regexOrAST: 'AST', type: IssueTypes.NC, title: '`public` functions not called by the contract should be declared `external` instead', diff --git a/src/issues/NC/uselessZeroInit.ts b/src/issues/NC/uselessZeroInit.ts index 7017397..11f9c9e 100644 --- a/src/issues/NC/uselessZeroInit.ts +++ b/src/issues/NC/uselessZeroInit.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'uselessZeroInit', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'Variables need not be initialized to zero', diff --git a/src/issues/NC/v2728check.ts b/src/issues/NC/v2728check.ts index 51bbca2..21c96d9 100644 --- a/src/issues/NC/v2728check.ts +++ b/src/issues/NC/v2728check.ts @@ -1,6 +1,7 @@ import { IssueTypes, RegexIssue } from '../../types'; const issue: RegexIssue = { + id: 'v2728check', regexOrAST: 'Regex', type: IssueTypes.NC, title: 'No need to check that `v == 27` or `v == 28` with `ecrecover`', From 7c96d6f45d9643746e67609b405642ffd1aa2f22 Mon Sep 17 00:00:00 2001 From: Eli Leers Date: Wed, 12 Feb 2025 13:22:50 -0800 Subject: [PATCH 15/20] Fix bug in skipDetectors --- src/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/index.ts b/src/index.ts index 7ba6855..9902721 100644 --- a/src/index.ts +++ b/src/index.ts @@ -25,7 +25,7 @@ program .option('--skip-low', 'Skip low issues') .option('--skip-medium', 'Skip medium issues') .option('--skip-high', 'Skip high issues') - .option('--skip, --skip-detectors [detectorID...]', 'Skip specific detectors by id') + .option('--skip, --skip-detectors ', 'Skip specific detectors by id') .action((basePath:string, options) => { basePath = basePath ||'contracts/'; basePath = basePath.endsWith('/') ? basePath : `${basePath}/`; @@ -39,7 +39,7 @@ program if(!options.skipMedium) severityToRun.push(IssueTypes.M); if(!options.skipHigh) severityToRun.push(IssueTypes.H); - const skipDetectors = options.skip || []; + const skipDetectors = options.skipDetectors || []; const skipDetectorsLower = skipDetectors.map(detector => detector.toLowerCase()); // Convert to lowercase to avoid case-sensitive issues console.log(`basePath: ${basePath}`); From 8e68d18593e5624031c9009fb722d7940b1b8660 Mon Sep 17 00:00:00 2001 From: Matthew Pilsbury Date: Tue, 22 Apr 2025 16:39:16 -0400 Subject: [PATCH 16/20] Add 15 detectors --- .gitignore | 3 +- src/issues/GAS/bytesConstantsVsString.ts | 11 ++++ src/issues/GAS/smallUintIncrement.ts | 11 ++++ src/issues/GAS/storageVsMemoryStructArray.ts | 14 +++++ src/issues/GAS/uncheckedIncrement.ts | 11 ++++ .../L/DivissionPrecissionLossASTParser.ts | 35 +++++++++++ src/issues/L/lowLevelCallsToCustomAddress.ts | 17 ++++++ src/issues/L/timestampReliance.ts | 13 ++++ src/issues/M/msgValueWithoutPayable.ts | 31 ++++++++++ src/issues/M/selfdestruct.ts | 13 ++++ src/issues/M/slippageValidation.ts | 18 ++++++ src/issues/M/supportsInterface.ts | 21 +++++++ src/issues/M/suspiciousSelfAssignment.ts | 60 +++++++++++++++++++ src/issues/M/uncheckedCallValueSuccess.ts | 13 ++++ src/issues/M/uncheckedSendSuccess.ts | 13 ++++ src/issues/NC/lineLength.ts | 12 ++++ 16 files changed, 295 insertions(+), 1 deletion(-) create mode 100644 src/issues/GAS/bytesConstantsVsString.ts create mode 100644 src/issues/GAS/smallUintIncrement.ts create mode 100644 src/issues/GAS/storageVsMemoryStructArray.ts create mode 100644 src/issues/GAS/uncheckedIncrement.ts create mode 100644 src/issues/L/DivissionPrecissionLossASTParser.ts create mode 100644 src/issues/L/lowLevelCallsToCustomAddress.ts create mode 100644 src/issues/L/timestampReliance.ts create mode 100644 src/issues/M/msgValueWithoutPayable.ts create mode 100644 src/issues/M/selfdestruct.ts create mode 100644 src/issues/M/slippageValidation.ts create mode 100644 src/issues/M/supportsInterface.ts create mode 100644 src/issues/M/suspiciousSelfAssignment.ts create mode 100644 src/issues/M/uncheckedCallValueSuccess.ts create mode 100644 src/issues/M/uncheckedSendSuccess.ts create mode 100644 src/issues/NC/lineLength.ts diff --git a/.gitignore b/.gitignore index 9e72fb7..98d8286 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ report.md .vscode/tasks.json scope.txt repos -reports \ No newline at end of file +reports +.DS_Store \ No newline at end of file diff --git a/src/issues/GAS/bytesConstantsVsString.ts b/src/issues/GAS/bytesConstantsVsString.ts new file mode 100644 index 0000000..75d8b24 --- /dev/null +++ b/src/issues/GAS/bytesConstantsVsString.ts @@ -0,0 +1,11 @@ +import { IssueTypes, RegexIssue } from '../../types'; + +const issue: RegexIssue = { + id: 'bytesConstantsVsString', + regexOrAST: 'Regex', + type: IssueTypes.GAS, + title: 'Bytes constants are more efficient than string constants', + regex: /string.+constant/g, +}; + +export default issue; diff --git a/src/issues/GAS/smallUintIncrement.ts b/src/issues/GAS/smallUintIncrement.ts new file mode 100644 index 0000000..bf7d40a --- /dev/null +++ b/src/issues/GAS/smallUintIncrement.ts @@ -0,0 +1,11 @@ +import { IssueTypes, RegexIssue } from '../../types'; + +const issue: RegexIssue = { + id: 'smallUintIncrement', + regexOrAST: 'Regex', + type: IssueTypes.GAS, + title: 'Incrementing with a smaller type than `uint256` incurs overhead', + regex: /for.+uint(?!(256| ))/g, +}; + +export default issue; diff --git a/src/issues/GAS/storageVsMemoryStructArray.ts b/src/issues/GAS/storageVsMemoryStructArray.ts new file mode 100644 index 0000000..57d006d --- /dev/null +++ b/src/issues/GAS/storageVsMemoryStructArray.ts @@ -0,0 +1,14 @@ +import { IssueTypes, RegexIssue } from '../../types'; + +const issue: RegexIssue = { + id: 'storageVsMemoryStructArray', + regexOrAST: 'Regex', + type: IssueTypes.GAS, + title: 'Use `storage` instead of `memory` for structs/arrays', + description: + 'Using `memory` copies the struct or array in memory. Use `storage` to save the location in storage and have cheaper reads:', + regex: /memory.+\=/g, + startLineModifier: 1, +}; + +export default issue; diff --git a/src/issues/GAS/uncheckedIncrement.ts b/src/issues/GAS/uncheckedIncrement.ts new file mode 100644 index 0000000..29e97cd --- /dev/null +++ b/src/issues/GAS/uncheckedIncrement.ts @@ -0,0 +1,11 @@ +import { IssueTypes, RegexIssue } from '../../types'; + +const issue: RegexIssue = { + id: 'uncheckedIncrement', + regexOrAST: 'Regex', + type: IssueTypes.GAS, + title: 'Increments can be `unchecked` in for-loops', + regex: /for.+\+\+/g, +}; + +export default issue; diff --git a/src/issues/L/DivissionPrecissionLossASTParser.ts b/src/issues/L/DivissionPrecissionLossASTParser.ts new file mode 100644 index 0000000..bd0da2b --- /dev/null +++ b/src/issues/L/DivissionPrecissionLossASTParser.ts @@ -0,0 +1,35 @@ +import { InputType, IssueTypes, Instance, ASTIssue } from '../../types'; +import { findAll } from 'solidity-ast/utils'; +import { instanceFromSRC } from '../../utils'; + +const issue: ASTIssue = { + id: 'divisionPrecissionLossASTParser', + regexOrAST: 'AST', + type: IssueTypes.L, + title: + 'Consider requiring a minimum amount for the numerator to ensure that it is always larger than the denominator.', + description: + 'Division by large numbers may result in the result being zero, due to Solidity not supporting fractions. Consider requiring a minimum amount for the numerator to ensure that it is always larger than the denominator.', + detector: (files: InputType): Instance[] => { + let instances: Instance[] = []; + + for (const file of files) { + if (!!file.ast) { + for (const node of findAll('BinaryOperation', file.ast)) { + // Look for Address(X).balance + if ( + node.nodeType === 'BinaryOperation' && + node.operator === '/' + // node.expression.nodeType === 'FunctionCall' && + // node.expression.typeDescriptions.typeString === 'address' + ) { + instances.push(instanceFromSRC(file, node.src)); + } + } + } + } + return instances; + }, +}; + +export default issue; \ No newline at end of file diff --git a/src/issues/L/lowLevelCallsToCustomAddress.ts b/src/issues/L/lowLevelCallsToCustomAddress.ts new file mode 100644 index 0000000..7940005 --- /dev/null +++ b/src/issues/L/lowLevelCallsToCustomAddress.ts @@ -0,0 +1,17 @@ +import { IssueTypes, RegexIssue } from '../../types'; + +const issue: RegexIssue = { + id: 'lowLevelCallsToCustomAddress', + regexOrAST: 'Regex', + type: IssueTypes.L, + title: + ' Low Level Calls to Custom Addresses', + description: + "Contracts should avoid making low-level calls to custom addresses, especially if these calls are based on address parameters in the function. Such behavior can lead to unexpected execution of untrusted code. Instead, consider using Solidity's high-level function calls or contract interactions.", + regex: /\(\w*\)[.]call\{\w*:\s+\w*\}\(\w*""\)/g, + +}; + +export default issue; +// This is my implementation of the issue M-01 Low level call to Custom address https://github.com/code-423n4/2023-10-ethena/blob/main/bot-report.md?fbclid=IwAR3IkbR6BhKSliDi2r-yRIU4tkGGbIPpBGHX7IA8NOAlMyatBN8o0BGF61I#l-08-function-parameters-in-public-accessible-functions-need-address0-check +//File: contracts/EthenaMinting.sol (bool success,) = (beneficiary).call{value: amount}(""); \ No newline at end of file diff --git a/src/issues/L/timestampReliance.ts b/src/issues/L/timestampReliance.ts new file mode 100644 index 0000000..5871761 --- /dev/null +++ b/src/issues/L/timestampReliance.ts @@ -0,0 +1,13 @@ +import { IssueTypes, RegexIssue } from '../../types'; + +const issue: RegexIssue = { + id: 'timestampReliance', + regexOrAST: 'Regex', + type: IssueTypes.M, + title: 'Timestamp Manipulation', + impact: 'On proof-of-work chains, miners can change the block timestamp. If critical operations depend upon these timestamps, or they are meant to be used as a source of pseudro-randmoness, they may be unsafe to use on PoW chains.', + regex: /(block\.timestamp|now|block\.blockhash\(block\.timestamp\))/g + , +}; + +export default issue; \ No newline at end of file diff --git a/src/issues/M/msgValueWithoutPayable.ts b/src/issues/M/msgValueWithoutPayable.ts new file mode 100644 index 0000000..5965944 --- /dev/null +++ b/src/issues/M/msgValueWithoutPayable.ts @@ -0,0 +1,31 @@ +import { IssueTypes, RegexIssue } from '../../types'; + +// Reference: https://github.com/sherlock-audit/2023-04-jojo/blob/6090fef68932b5577abf6b5aa26eb1e579353c57/smart-contract-EVM/contracts/subaccount/Subaccount.sol#L45-L58 + +// function execute(address to, bytes calldata data, uint256 value) external onlyOwner returns (bytes memory){ +// require(to != address(0)); +// (bool success, bytes memory returnData) = to.call{value: value}(data); +// if (!success) { +// assembly { +// let ptr := mload(0x40) +// let size := returndatasize() +// returndatacopy(ptr, 0, size) +// revert(ptr, size) +// } +// } +// emit ExecuteTransaction(owner, address(this), to, data, value); +// return returnData; +// } + +const issue: RegexIssue = { + id: 'msgValueWithoutPayable', + regexOrAST: 'Regex', + type: IssueTypes.M, + title: 'Function uses `call{value}` but does not have the `payable` modifier', + impact: + 'The function uses msg.value indirectly through a `call{value}`, but does not have the payable modifier, which is required for any function that handles ether transfers.', + regex: + /function\s+(\w+)\s*\([^)]*\)\s*(external\s+)?(public\s+)?(internal\s+)?(private\s+)?(view\s+)?(pure\s+)?override\s*?(?!\s*payable)[^{]*\{\s*(?:[^}]*\.call\s*\{[^}]*value:[^}]*\}|[^}]*msg\.value[^}]*)[^}]*\}/g, +}; + +export default issue; \ No newline at end of file diff --git a/src/issues/M/selfdestruct.ts b/src/issues/M/selfdestruct.ts new file mode 100644 index 0000000..3ae8985 --- /dev/null +++ b/src/issues/M/selfdestruct.ts @@ -0,0 +1,13 @@ +import { IssueTypes, RegexIssue } from '../../types'; + +const issue: RegexIssue = { + id: 'selfdestruct', + regexOrAST: 'Regex', + type: IssueTypes.M, + title: 'Used selfdestruct', + impact: 'Any contract that depends on another smart contract must account for the fact that the other can vanish at any time. Moreover, the SELFDESTRUCT opcode is deprecated and is recommended to no longer be used.', + regex: /selfdestruct\([a-zA-Z0-9\.\(\)]+\)/g + , +}; + +export default issue; \ No newline at end of file diff --git a/src/issues/M/slippageValidation.ts b/src/issues/M/slippageValidation.ts new file mode 100644 index 0000000..ed5fdc0 --- /dev/null +++ b/src/issues/M/slippageValidation.ts @@ -0,0 +1,18 @@ +import { IssueTypes, RegexIssue } from '../../types'; + +// Reference: https://github.com/jbx-protocol/juice-buyback/blob/d0ea50010b2f01d1602522e7b3b2e3c9b927b49c/contracts/JBXBuybackDelegate.sol#L196C12-L197 + +// (,, uint256 _quote, uint256 _slippage) = abi.decode(_data.metadata, (bytes32, bytes32, uint256, uint256)); +// uint256 _minimumReceivedFromSwap = _quote - (_quote * _slippage / SLIPPAGE_DENOMINATOR); + +const issue: RegexIssue = { + id: 'slippageValidation', + regexOrAST: 'Regex', + type: IssueTypes.M, + title: 'Lack of slippage validation can lead to user loss of funds', + impact: + 'The slippage parameter should be validated against its denominator in order to prevent user mistake and potential loss of funds.', + regex: /function[^{]+\{[^}]*?\b(\w*slippage\w*)\b[^}]*?(?!require\s*\(\s*\1\s*<=)[^}]*?\}/gis, +}; + +export default issue; \ No newline at end of file diff --git a/src/issues/M/supportsInterface.ts b/src/issues/M/supportsInterface.ts new file mode 100644 index 0000000..0547397 --- /dev/null +++ b/src/issues/M/supportsInterface.ts @@ -0,0 +1,21 @@ +import { IssueTypes, RegexIssue } from '../../types'; + +// Reference: https://github.com/jbx-protocol/juice-buyback/blob/d0ea50010b2f01d1602522e7b3b2e3c9b927b49c/contracts/JBXBuybackDelegate.sol + +// function supportsInterface(bytes4 _interfaceId) external pure override returns (bool) { +// return _interfaceId == type(IJBFundingCycleDataSource).interfaceId +// || _interfaceId == type(IJBPayDelegate).interfaceId; +// } + +const issue: RegexIssue = { + id: 'supportsInterface', + regexOrAST: 'Regex', + type: IssueTypes.M, + title: 'Contract is not compliant with ERC-165', + impact: + 'In order to properly implement `supportsInterface` in accordance with the ERC-165, the function MUST return true for the interface ID parameter `0x01ffc9a7` (calculated from `bytes4(keccak256("supportsInterface(bytes4)"))`), or simply `type(ERC165).interfaceId`.', + regex: + /function\s+supportsInterface\((bytes4\s+)?.*\)\s+(external\s+)?(public\s+)?(pure\s+|view\s+)?override\s+returns\s*\(bool\)\s*\{(?![^}]*(.*\s*==\s*0x01ffc9a7|.*\s*==\s*type\(ERC165\)\.interfaceId))[^}]*\}/g, +}; + +export default issue; \ No newline at end of file diff --git a/src/issues/M/suspiciousSelfAssignment.ts b/src/issues/M/suspiciousSelfAssignment.ts new file mode 100644 index 0000000..30a42df --- /dev/null +++ b/src/issues/M/suspiciousSelfAssignment.ts @@ -0,0 +1,60 @@ +import { InputType, IssueTypes, Instance, ASTIssue } from '../../types'; +import { findAll } from 'solidity-ast/utils'; +import { instanceFromSRC } from '../../utils'; +import { Expression } from 'solidity-ast'; + +// Iterative compare function to compare left and right nodes. +function compare(left: Expression | null | undefined, right: Expression | null | undefined): boolean { + // If null/undefined, return false + if (left == null || right == null) return false; + // If nodeType Not equal, return false + if (left.nodeType != right.nodeType) return false; + + // Literal + if (left.nodeType == "Literal" && right.nodeType == "Literal") { + return left.value == right.value; + } + + // Identifier + if (left.nodeType == "Identifier" && right.nodeType == "Identifier") { + return left.name == right.name; + } + + // IndexAccess + if (left.nodeType == "IndexAccess" && right.nodeType == "IndexAccess") { + let base = compare(left.baseExpression,right.baseExpression) + let index = compare(left.indexExpression,right.indexExpression); + return base && index; + } + + return false; +} + +const issue: ASTIssue = { + id: 'suspiciousSelfAssignment', + regexOrAST: 'AST', + type: IssueTypes.M, + title: 'Suspicious Self Assignment', + description: 'A self-assignment occurs when a variable or state is assigned a value that is already held by that variable or state itself. This situation often indicates a potential issue in the code, which can be redundant or incorrect. Specifically, self-assignment might suggest that the value assignment does not change the state of the variable, or it could be a sign of a logical error.', + detector: (files: InputType): Instance[] => { + let instances: Instance[] = []; + + for (const file of files) { + if (!!file.ast) { + for (const node of findAll('Assignment', file.ast)) { + let hit = false; + + hit = compare(node.leftHandSide,node.rightHandSide); + + if (hit) { + instances.push(instanceFromSRC(file, node.src)); + } + + } + } + } + return instances; + }, +}; + +export default issue; diff --git a/src/issues/M/uncheckedCallValueSuccess.ts b/src/issues/M/uncheckedCallValueSuccess.ts new file mode 100644 index 0000000..111988e --- /dev/null +++ b/src/issues/M/uncheckedCallValueSuccess.ts @@ -0,0 +1,13 @@ +import { IssueTypes, RegexIssue } from '../../types'; + +const issue: RegexIssue = { + id: 'uncheckedCallValueSuccess', + regexOrAST: 'Regex', + type: IssueTypes.M, + title: + 'Call.value fallback function reversion risk', + description: "Make sure the return boolean of the call function with value is true, otherwise contract risks assuming value has left when not if the fallback function of the destination reverts or is not payable.", + regex: /(? Date: Wed, 23 Apr 2025 13:02:38 -0400 Subject: [PATCH 17/20] Update repo link in SARIF --- src/sarif.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sarif.ts b/src/sarif.ts index b5af911..09bf347 100644 --- a/src/sarif.ts +++ b/src/sarif.ts @@ -172,7 +172,7 @@ const sarif = (analyses: Analysis[]): Object => { driver: { name: "4naly3er", fullName: "4naly3er Static Smart Contract Code Analyzer", - informationUri: "https://github.com/AnalyticETH/4naly3er", + informationUri: "https://github.com/cb-elileers/analyze", version: "0.2", // Update the version number rules: analyses.map((item, index) => ({ id: `rule${index + 1}`, @@ -183,7 +183,7 @@ const sarif = (analyses: Analysis[]): Object => { fullDescription: { text: item.issue.description || item.issue.title }, - helpUri: "https://github.com/AnalyticETH/4naly3er/blob/analytic/detectors.md", + helpUri: "https://github.com/cb-elileers/analyze/blob/analytic/detectors.md", help: { text: item.issue.description || item.issue.title }, From 6c4e9b8c9e07ee51359d744bf982fb214099c945 Mon Sep 17 00:00:00 2001 From: Matt Pilsbury Date: Wed, 23 Apr 2025 15:46:33 -0400 Subject: [PATCH 18/20] Update sarif.ts --- src/sarif.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sarif.ts b/src/sarif.ts index 09bf347..ef3fd4d 100644 --- a/src/sarif.ts +++ b/src/sarif.ts @@ -172,7 +172,7 @@ const sarif = (analyses: Analysis[]): Object => { driver: { name: "4naly3er", fullName: "4naly3er Static Smart Contract Code Analyzer", - informationUri: "https://github.com/cb-elileers/analyze", + informationUri: "https://github.com/cb-elileers/analyzer", version: "0.2", // Update the version number rules: analyses.map((item, index) => ({ id: `rule${index + 1}`, @@ -183,7 +183,7 @@ const sarif = (analyses: Analysis[]): Object => { fullDescription: { text: item.issue.description || item.issue.title }, - helpUri: "https://github.com/cb-elileers/analyze/blob/analytic/detectors.md", + helpUri: "https://github.com/cb-elileers/analyzer/blob/analytic/detectors.md", help: { text: item.issue.description || item.issue.title }, From 5ec43ebdd28d1790a3e828643782dc50fcfcab65 Mon Sep 17 00:00:00 2001 From: Eli Leers Date: Wed, 23 Apr 2025 13:58:41 -0700 Subject: [PATCH 19/20] Update recursiveExploration function to have a parameter for skipping directories, and added a few directories to autoskip that were causing runs to fail --- src/utils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils.ts b/src/utils.ts index 1209d81..0ede1c7 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -45,7 +45,7 @@ export async function sh(cmd: string) { * @notice Returns all file contained in a folder * @dev Works with a queue, could be done with a recursive function */ -export const recursiveExploration = (basePath: string, extension = '.sol'): string[] => { +export const recursiveExploration = (basePath: string, extension = '.sol', skipDirs: string[] = ['test', 'lib', 'script', 'node_modules', '.git']): string[] => { let fileNames: string[] = []; let directoryQueue = ['']; while (directoryQueue.length > 0) { @@ -54,7 +54,7 @@ export const recursiveExploration = (basePath: string, extension = '.sol'): stri for (let fileName of tempFileNames) { fileName = `${dir}${fileName}`; if (fs.statSync(`${basePath}${fileName}`).isDirectory()) { - if (fileName != "test" && fileName != "lib" && fileName != "script"){ // skip test and lib folders + if (!skipDirs.includes(fileName)) { // skip directories from skipDirs array directoryQueue.push(fileName + '/'); } } else if (fileName.endsWith(extension)) { From 3fb8c6daed379cf34dbd09296e2f127c86284d50 Mon Sep 17 00:00:00 2001 From: Eli Leers Date: Wed, 23 Apr 2025 14:07:32 -0700 Subject: [PATCH 20/20] Update usage instructions in readme --- README.md | 61 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 2911e83..924a032 100644 --- a/README.md +++ b/README.md @@ -15,20 +15,61 @@ - [Installation](#installation) - [Contributing](#contributing) -## Usage +### Installing 4naly3er -```bash -yarn analyze +#### Prerequisites: + +You must have `node` and `yarn` installed on your system. + +#### Installation: + +``` +git clone [https://github.com/cb-elileers/analyzer](https://github.cbhq.net/security/solidity-analyzer) +cd analyzer +npm i --force --save-dev +yarn +``` + +## Using 4naly3er -# Example -yarn analyze contracts scope.example.txt +#### Basic Usage + +``` +yarn analyze ``` -- `BASE_PATH` is a relative path to the folder containing the smart contracts. -- `SCOPE_FILE` is an optional file containing a specific smart contracts scope (see [scope.example.txt](./scope.example.txt)) -- `GITHUB_URL` is an optional url to generate links to github in the report -- For remappings, add `remappings.txt` to `BASE_PATH`. -- The output will be saved in a `report.md` file. +For example: `yarn analyze ~/Documents/op-enclave/` + +**Where Options Are:** + +- BASE_PATH is a **required** parameter which points to the folder containing the smart contract project. +- '-s, --scope scopeFile' .txt file containing the contest scope +- '-g, --github githubURL' github url to generate links to code +- '-o, --out reportPath' Path for Markdown report +- '-l, --listfiles' List analyzed files in Markdown Report +- '--legacyscope scopeFile' Path for legacy scope file +- '--sarif [outputPath]' Generate SARIF report, optionally include path to report. Default is analyzer.sarif +- '--skip-info' Skip info issues +- '--skip-gas' Skip gas issues +- '--skip-low' Skip low issues +- '--skip-medium' Skip medium issues +- '--skip-high' Skip high issues +- '--skip, --skip-detectors detectorID' Skip specific detectors by id + +For any remappings, Forge can generate, or you can add, remappings.txt to the BASE_PATH and 4naly3er will use them accordingly. + +Output from the tool is stored in **report.md** within the 4naly3er folder. To keep all documents related to a project together, it is advisable to run `mv report.md ` to deposit the report into the smart contract project's folder. (Click here to see an example report)[https://gist.github.com/Picodes/e9f1bb87ae832695694175abd8f9797f] + +#### Scope File Generation + +Sometimes, we only want to run our tooling on certain contracts within a repository. To do so, we define those contracts we want to be in scope in a **scope.txt** file. + +To autogenerate a scope.txt file that excludes dependencies, we can use the below script: + +``` +cd +find . | grep "\.sol" | grep -v "\./lib/" | grep -v typechain | grep -v node_modules | grep -v artifacts | grep -v "\.t\.sol">scope.txt +``` ## Example Reports