├── .coveralls.yml
├── .dockerignore
├── .eslintignore
├── .eslintrc.js
├── .gitattributes
├── .github
└── workflows
│ ├── DOCKER.yml
│ ├── E2E.yml
│ ├── PRE-COMMIT-HOOK-TEST.yml
│ └── TESTS.yml
├── .gitignore
├── .pre-commit-hooks.yaml
├── .prettierrc
├── CHANGELOG.md
├── DEV-README.md
├── LICENSE
├── README.md
├── _config.yml
├── conf
└── rulesets
│ ├── solhint-all.js
│ └── solhint-recommended.js
├── docker
├── Dockerfile
└── docker.md
├── docs
├── _config.yml
├── _includes
│ ├── head.html
│ ├── page-footer.html
│ └── page-header.html
├── _layouts
│ └── default.html
├── architecture.md
├── configuration.md
├── contributing.md
├── css
│ ├── cayman.css
│ └── normalize.css
├── rules.md
├── rules
│ ├── best-practices
│ │ ├── code-complexity.md
│ │ ├── constructor-syntax.md
│ │ ├── explicit-types.md
│ │ ├── function-max-lines.md
│ │ ├── max-line-length.md
│ │ ├── max-states-count.md
│ │ ├── no-console.md
│ │ ├── no-empty-blocks.md
│ │ ├── no-global-import.md
│ │ ├── no-unused-import.md
│ │ ├── no-unused-vars.md
│ │ ├── one-contract-per-file.md
│ │ ├── payable-fallback.md
│ │ └── reason-string.md
│ ├── gas-consumption
│ │ ├── gas-calldata-parameters.md
│ │ ├── gas-custom-errors.md
│ │ ├── gas-increment-by-one.md
│ │ ├── gas-indexed-events.md
│ │ ├── gas-length-in-loops.md
│ │ ├── gas-multitoken1155.md
│ │ ├── gas-named-return-values.md
│ │ ├── gas-small-strings.md
│ │ ├── gas-strict-inequalities.md
│ │ └── gas-struct-packing.md
│ ├── miscellaneous
│ │ ├── comprehensive-interface.md
│ │ ├── duplicated-imports.md
│ │ ├── import-path-check.md
│ │ └── quotes.md
│ ├── naming
│ │ ├── const-name-snakecase.md
│ │ ├── contract-name-camelcase.md
│ │ ├── contract-name-capwords.md
│ │ ├── event-name-camelcase.md
│ │ ├── event-name-capwords.md
│ │ ├── event-name-pascalcase.md
│ │ ├── foundry-test-functions.md
│ │ ├── func-name-mixedcase.md
│ │ ├── func-named-parameters.md
│ │ ├── func-param-name-mixedcase.md
│ │ ├── immutable-vars-naming.md
│ │ ├── imports-order.md
│ │ ├── interface-starts-with-i.md
│ │ ├── modifier-name-mixedcase.md
│ │ ├── named-parameters-mapping.md
│ │ ├── private-vars-leading-underscore.md
│ │ ├── use-forbidden-name.md
│ │ └── var-name-mixedcase.md
│ ├── order
│ │ ├── func-order.md
│ │ ├── imports-on-top.md
│ │ ├── ordering.md
│ │ └── visibility-modifier-order.md
│ └── security
│ │ ├── avoid-call-value.md
│ │ ├── avoid-low-level-calls.md
│ │ ├── avoid-sha3.md
│ │ ├── avoid-suicide.md
│ │ ├── avoid-throw.md
│ │ ├── avoid-tx-origin.md
│ │ ├── check-send-result.md
│ │ ├── compiler-version.md
│ │ ├── func-visibility.md
│ │ ├── multiple-sends.md
│ │ ├── no-complex-fallback.md
│ │ ├── no-inline-assembly.md
│ │ ├── not-rely-on-block-hash.md
│ │ ├── not-rely-on-time.md
│ │ ├── reentrancy.md
│ │ └── state-visibility.md
├── shareable-configs.md
├── use-in-app.md
└── writing-plugins.md
├── e2e
├── 01-no-config
│ └── Foo.sol
├── 02-empty-solhint-json
│ ├── .solhint.json
│ └── Foo.sol
├── 03-no-empty-blocks
│ ├── .solhint.json
│ └── Foo.sol
├── 04-dotSol-on-path
│ ├── .solhint.json
│ └── contracts
│ │ └── ERC20.sol
│ │ ├── ERC20.dbg.js
│ │ └── Foo.sol
├── 05-max-warnings
│ ├── .solhint.json
│ └── contracts
│ │ ├── Foo.sol
│ │ └── Foo2.sol
├── 06-formatters
│ ├── .solhint.json
│ ├── contracts
│ │ ├── Foo.sol
│ │ ├── Foo2.sol
│ │ └── Foo3.sol
│ └── helpers
│ │ └── helpers.js
├── 07-foundry-test
│ ├── .solhint.json
│ ├── contracts
│ │ └── Foo.sol
│ └── test
│ │ ├── .solhint.json
│ │ ├── FooTest.sol
│ │ └── Test.sol
├── 08-autofix
│ ├── _commands
│ │ ├── .solhint.json
│ │ ├── Foo1.sol
│ │ ├── Foo1AfterFix.sol
│ │ └── Foo1BeforeFix.sol
│ ├── avoid-suicide
│ │ ├── .solhint.json
│ │ ├── Foo1.sol
│ │ ├── Foo1AfterFix.sol
│ │ └── Foo1BeforeFix.sol
│ ├── contract-name-capwords
│ │ ├── .solhint.json
│ │ ├── Foo1.sol
│ │ ├── Foo1AfterFix.sol
│ │ └── Foo1BeforeFix.sol
│ ├── event-name-capwords
│ │ ├── .solhint.json
│ │ ├── Foo1.sol
│ │ ├── Foo1AfterFix.sol
│ │ └── Foo1BeforeFix.sol
│ ├── explicit-types
│ │ ├── .solhint.json
│ │ ├── Foo1.sol
│ │ ├── Foo1AfterFix.sol
│ │ └── Foo1BeforeFix.sol
│ ├── imports-order
│ │ ├── .solhint.json
│ │ ├── Foo1.sol
│ │ ├── Foo1AfterFix.sol
│ │ ├── Foo1BeforeFix.sol
│ │ ├── Foo2.sol
│ │ ├── Foo2AfterFix.sol
│ │ └── Foo2BeforeFix.sol
│ ├── no-console
│ │ ├── .solhint.json
│ │ ├── Foo1.sol
│ │ ├── Foo1AfterFix.sol
│ │ └── Foo1BeforeFix.sol
│ ├── no-unused-import
│ │ ├── .solhint.json
│ │ ├── Foo1.sol
│ │ ├── Foo1AfterFix.sol
│ │ └── Foo1BeforeFix.sol
│ ├── payable-fallback
│ │ ├── .solhint.json
│ │ ├── Foo1.sol
│ │ ├── Foo1AfterFix.sol
│ │ └── Foo1BeforeFix.sol
│ ├── private-vars-underscore
│ │ ├── .solhint.json
│ │ ├── Foo1.sol
│ │ ├── Foo1AfterFix.sol
│ │ └── Foo1BeforeFix.sol
│ └── quotes
│ │ ├── .doubleQuotes.json
│ │ ├── .singleQuotes.json
│ │ ├── Foo1.sol
│ │ ├── Foo1AfterFixDouble.sol
│ │ ├── Foo1AfterFixSingle.sol
│ │ └── Foo1BeforeFix.sol
├── 10-import-path-check
│ ├── filesystem01
│ │ └── project
│ │ │ ├── .solhintS01.json
│ │ │ └── contracts
│ │ │ ├── Lib.sol
│ │ │ └── Test.sol
│ ├── filesystem02
│ │ └── project
│ │ │ ├── .solhintS02.json
│ │ │ ├── contracts
│ │ │ └── Test.sol
│ │ │ └── shared
│ │ │ └── Helper.sol
│ ├── filesystem03
│ │ └── project
│ │ │ ├── .solhintS03.json
│ │ │ └── contracts
│ │ │ └── Test.sol
│ └── filesystem04
│ │ └── project
│ │ ├── .solhintF04.json
│ │ └── contracts
│ │ └── Test.sol
├── autofix-test.js
├── formatters-test.js
├── pre-commit-hook
│ ├── .solhint.json
│ ├── Counter.sol
│ └── test.sh
└── test.js
├── funding.json
├── lib
├── apply-fixes.js
├── comment-directive-parser.js
├── common
│ ├── ajv.js
│ ├── ast-printer.js
│ ├── ast-types.js
│ ├── blank-line-counter.js
│ ├── errors.js
│ ├── identifier-naming.js
│ ├── statements-indent-validator.js
│ ├── tokens.js
│ ├── tree-traversing.js
│ └── utils.js
├── config.js
├── config
│ ├── config-file.js
│ ├── config-schema.js
│ └── config-validator.js
├── doc
│ └── utils.js
├── formatters
│ ├── LICENSE
│ ├── README.md
│ ├── compact.js
│ ├── json.js
│ ├── sarif.js
│ ├── stylish.js
│ ├── table.js
│ ├── tap.js
│ └── unix.js
├── index.js
├── load-rules.js
├── reporter.js
├── rule-fixer.js
├── rules
│ ├── base-checker.js
│ ├── best-practices
│ │ ├── code-complexity.js
│ │ ├── explicit-types.js
│ │ ├── function-max-lines.js
│ │ ├── index.js
│ │ ├── interface-starts-with-i.js
│ │ ├── max-line-length.js
│ │ ├── max-states-count.js
│ │ ├── no-console.js
│ │ ├── no-empty-blocks.js
│ │ ├── no-global-import.js
│ │ ├── no-unused-import.js
│ │ ├── no-unused-vars.js
│ │ ├── one-contract-per-file.js
│ │ ├── payable-fallback.js
│ │ └── reason-string.js
│ ├── deprecations
│ │ ├── base-deprecation.js
│ │ ├── constructor-syntax.js
│ │ └── index.js
│ ├── gas-consumption
│ │ ├── gas-calldata-parameters.js
│ │ ├── gas-custom-errors.js
│ │ ├── gas-increment-by-one.js
│ │ ├── gas-indexed-events.js
│ │ ├── gas-length-in-loops.js
│ │ ├── gas-multitoken1155.js
│ │ ├── gas-named-return-values.js
│ │ ├── gas-small-strings.js
│ │ ├── gas-strict-inequalities.js
│ │ ├── gas-struct-packing.js
│ │ └── index.js
│ ├── index.js
│ ├── miscellaneous
│ │ ├── comprehensive-interface.js
│ │ ├── duplicated-imports.js
│ │ ├── import-path-check.js
│ │ ├── index.js
│ │ └── quotes.js
│ ├── naming
│ │ ├── const-name-snakecase.js
│ │ ├── contract-name-capwords.js
│ │ ├── event-name-capwords.js
│ │ ├── foundry-test-functions.js
│ │ ├── func-name-mixedcase.js
│ │ ├── func-named-parameters.js
│ │ ├── func-param-name-mixedcase.js
│ │ ├── immutable-vars-naming.js
│ │ ├── index.js
│ │ ├── modifier-name-mixedcase.js
│ │ ├── named-parameters-mapping.js
│ │ ├── private-vars-leading-underscore.js
│ │ ├── use-forbidden-name.js
│ │ └── var-name-mixedcase.js
│ ├── order
│ │ ├── imports-on-top.js
│ │ ├── imports-order.js
│ │ ├── index.js
│ │ ├── ordering.js
│ │ └── visibility-modifier-order.js
│ └── security
│ │ ├── avoid-call-value.js
│ │ ├── avoid-low-level-calls.js
│ │ ├── avoid-sha3.js
│ │ ├── avoid-suicide.js
│ │ ├── avoid-throw.js
│ │ ├── avoid-tx-origin.js
│ │ ├── check-send-result.js
│ │ ├── compiler-version.js
│ │ ├── func-visibility.js
│ │ ├── index.js
│ │ ├── multiple-sends.js
│ │ ├── no-complex-fallback.js
│ │ ├── no-inline-assembly.js
│ │ ├── not-rely-on-block-hash.js
│ │ ├── not-rely-on-time.js
│ │ ├── reentrancy.js
│ │ └── state-visibility.js
└── tree-listener.js
├── package-lock.json
├── package.json
├── scripts
├── check-changes.js
├── generate-rule-docs.js
└── generate-rulesets.js
├── solhint-icon.png
├── solhint.js
├── solhint.png
└── test
├── common
├── apply-extends.js
├── apply-fixes.js
├── asserts.js
├── config-file.js
├── config-validator.js
├── contract-builder.js
├── errors.js
├── load-rules.js
└── utils.js
├── fixtures
├── align
│ ├── array_declaration.js
│ ├── array_declaration_with_spaces.js
│ ├── correctly_aligned_function_brackets.js
│ ├── correctly_indented_contract.js
│ ├── expression_with_mixed_tabs_and_spaces.js
│ ├── expressions_with_correct_comma_align.js
│ ├── expressions_with_correct_indents.js
│ ├── expressions_with_correct_semicolon_align.js
│ ├── expressions_with_incorrect_comma_align.js
│ ├── expressions_with_incorrect_indents.js
│ ├── expressions_with_incorrect_semicolon_align.js
│ ├── incorrectly_aligned_forloop_brackets.js
│ ├── incorrectly_aligned_function_brackets.js
│ ├── incorrectly_indented_contract.js
│ ├── statements_with_correct_indents.js
│ └── statements_with_incorrect_indents.js
├── best-practices
│ ├── --fallback-not-payable.js
│ ├── --fallback-payable.js
│ ├── code-complexity-high.js
│ ├── code-complexity-low.js
│ ├── explicit-types.js
│ ├── number-of-states-high.js
│ ├── number-of-states-low.js
│ ├── one-contract-per-file.js
│ ├── require-with-reason.js
│ └── require-without-reason.js
├── gas-consumption
│ └── gas-struct-packing-data.js
├── miscellaneous
│ ├── duplicated-imports-data.js
│ ├── import-path-check.js
│ ├── public-function-no-override.js
│ ├── public-function-with-override.js
│ ├── string-with-double-quotes.js
│ └── string-with-single-quotes.js
├── naming
│ ├── func-named-parameters.js
│ └── named-parameters-mapping.js
├── order
│ ├── ordering-correct.js
│ ├── ordering-incorrect.js
│ ├── visibility-modifier-first.js
│ └── visibility-modifier-not-first.js
└── security
│ ├── contracts-with-free-functions.js
│ ├── functions-with-visibility.js
│ ├── functions-without-visibility.js
│ ├── low-level-calls.js
│ ├── reentrancy-invulnerable.js
│ └── reentrancy-vulnerable.js
├── helpers
└── solhint_config_test.json
├── parse-error.js
└── rules
├── best-practices
├── code-complexity.js
├── explicit-types.js
├── function-max-lines.js
├── interface-starts-with-i.js
├── max-line-length.js
├── max-states-count.js
├── no-console.js
├── no-empty-blocks.js
├── no-global-import.js
├── no-unused-import.js
├── no-unused-vars.js
├── one-contract-per-file.js
├── payable-fallback.js
└── reason-string.js
├── deprecations
└── constructor-syntax.js
├── gas-consumption
├── gas-calldata-parameters.js
├── gas-custom-errors.js
├── gas-increment-by-one.js
├── gas-indexed-events.js
├── gas-length-in-loops.js
├── gas-multitoken1155.js
├── gas-named-return-values.js
├── gas-small-strings.js
├── gas-strict-inequalities.js
└── gas-struct-packing.js
├── miscellaneous
├── comprehensive-interface.js
├── duplicated-imports.js
├── import-path-check.js
└── quotes.js
├── naming
├── const-name-snakecase.js
├── contract-name-capwords.js
├── event-name-capwords.js
├── foundry-test-functions.js
├── func-name-mixedcase.js
├── func-named-parameters.js
├── func-param-name-mixedcase.js
├── immutable-vars-naming.js
├── modifier-name-mixedcase.js
├── named-parameters-mapping.js
├── private-vars-leading-underscore.js
├── use-forbidden-name.js
└── var-name-mixedcase.js
├── order
├── imports-on-top.js
├── ordering.js
└── visibility-modifier-order.js
└── security
├── avoid-call-value.js
├── avoid-low-level-calls.js
├── avoid-sha3.js
├── avoid-suicide.js
├── avoid-throw.js
├── avoid-tx-origin.js
├── check-send-result.js
├── compiler-version.js
├── func-visibility.js
├── multiple-sends.js
├── no-complex-fallback.js
├── no-inline-assembly.js
├── not-rely-on-block-hash.js
├── not-rely-on-time.js
├── reentrancy.js
└── state-visibility.js
/.coveralls.yml:
--------------------------------------------------------------------------------
1 | repo_token: mkBlONxsK3bKnfkvXoIJRg8AmpBaBeLp4
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | .git/
2 | node_modules/
3 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | coverage
2 | node_modules
3 | e2e
4 | /_temp
5 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | parserOptions: {
3 | ecmaVersion: 2020,
4 | },
5 | env: {
6 | browser: false,
7 | node: true,
8 | commonjs: true,
9 | es6: true,
10 | mocha: true,
11 | },
12 | extends: ['airbnb-base', 'plugin:prettier/recommended'],
13 | rules: {
14 | 'consistent-return': 'off',
15 | 'import/no-dynamic-require': 'off',
16 | 'max-classes-per-file': 'off',
17 | 'import/no-extraneous-dependencies': ['error', { optionalDependencies: true }],
18 | 'global-require': 'off',
19 | 'no-bitwise': 'off',
20 | 'no-console': 'off',
21 | 'func-names': 'off',
22 | 'no-continue': 'off',
23 | 'no-else-return': 'off',
24 | 'no-param-reassign': 'off',
25 | 'no-plusplus': 'off',
26 | 'no-restricted-properties': 'off',
27 | 'no-restricted-syntax': 'off',
28 | 'no-use-before-define': ['error', { classes: false, functions: false }],
29 | 'prefer-destructuring': 'off',
30 | 'prefer-template': 'off',
31 |
32 | // this rules were disabled to make it easier to add airbnb-base, but they are good ones; we should re-enable them
33 | // at some point
34 | 'class-methods-use-this': 'off',
35 | 'guard-for-in': 'off',
36 | 'no-shadow': 'off',
37 | 'no-underscore-dangle': 'off',
38 | },
39 | }
40 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # prevent github actions to checkout files with crlf line endings
2 | * -text
3 |
--------------------------------------------------------------------------------
/.github/workflows/DOCKER.yml:
--------------------------------------------------------------------------------
1 | name: Docker Image CI
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | version:
7 | description: 'Solhint version'
8 | required: true
9 | image_name:
10 | description: 'Name of image to be used on docker hub'
11 | required: true
12 | default: 'protodb/protofire-solhint'
13 | jobs:
14 |
15 | build:
16 |
17 | runs-on: ubuntu-latest
18 |
19 | steps:
20 | - uses: actions/checkout@v4
21 |
22 | - name: Login to Docker Hub
23 | run: docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_ACCESS_TOKEN }}
24 |
25 | - name: Build Docker image
26 | run: docker build . --file docker/Dockerfile --tag ${{ inputs.image_name }}:latest --build-arg VERSION=${{ inputs.version }}
27 |
28 | - name: Push Docker image to Docker Hub
29 | run: docker push ${{ inputs.image_name }}:latest
30 |
--------------------------------------------------------------------------------
/.github/workflows/PRE-COMMIT-HOOK-TEST.yml:
--------------------------------------------------------------------------------
1 | name: PRE-COMMIT
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | - develop
8 | tags:
9 | - '*'
10 | pull_request:
11 | paths:
12 | - .github/workflows/PRE-COMMIT-HOOK-TEST.yml
13 | - .pre-commit-hooks.yaml
14 | - e2e/pre-commit-hook/*
15 | - package.json
16 |
17 | jobs:
18 | hook-test:
19 | runs-on: ubuntu-latest
20 | name: Test Hook
21 | steps:
22 | - uses: actions/checkout@v4
23 | - uses: actions/setup-node@v4
24 | with:
25 | node-version: 20
26 | - uses: actions/setup-python@v5
27 | with:
28 | python-version: '3.12'
29 | - name: Install pre-commit
30 | run: |
31 | python -m pip install pre-commit
32 | - name: Test hooks
33 | run: |
34 | ./e2e/pre-commit-hook/test.sh
35 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | /.idea/
3 | test2.sol
4 | convertLib.sol
5 | /.nyc_output/
6 | /coverage/
7 | /docs/_site/
8 | /docs/Gemfile*
9 | antlr4.jar
10 | /docs/.sass-cache/
11 | _temp/
12 | *solhintReport*.*
13 | .env
14 | **/.DS_Store
15 | solhint*.tgz
16 |
--------------------------------------------------------------------------------
/.pre-commit-hooks.yaml:
--------------------------------------------------------------------------------
1 | - id: solhint
2 | name: solhint
3 | description: Lint Solidity files with Solhint
4 | entry: solhint
5 | types: ["solidity"]
6 | language: node
7 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "semi": false,
3 | "singleQuote": true,
4 | "printWidth": 100,
5 | "bracketSpacing": true
6 | }
7 |
--------------------------------------------------------------------------------
/DEV-README.md:
--------------------------------------------------------------------------------
1 | ## Setting up Git Hooks
2 |
3 | After cloning the repository, set up the pre-commit hook by running the following commands:
4 |
5 | `git config --unset core.hooksPath`
6 | To reset the hooks config to git default
7 |
8 | ```sh
9 | touch .git/hooks/pre-commit
10 | chmod +x .git/hooks/pre-commit
11 | echo '#!/bin/sh\nnode scripts/check-changes.js' > .git/hooks/pre-commit
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017-2025 Protofire
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | plugins:
2 | - jekyll-relative-links
3 | relative_links:
4 | enabled: true
5 | collections: true
6 | include:
7 | - README.md
8 | - docs
9 |
--------------------------------------------------------------------------------
/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:20-alpine
2 | LABEL maintainer="diego.bale@protofire.io"
3 | ENV VERSION=5.1.0
4 |
5 | RUN npm install -g solhint@"$VERSION"
--------------------------------------------------------------------------------
/docker/docker.md:
--------------------------------------------------------------------------------
1 | # Docker Instructions
2 | Thanks to [@kaypee90](https://github.com/kaypee90) for the contribution
3 |
4 | 1. Get the image. Run:
5 | `docker pull protodb/protofire-solhint:latest`
6 |
7 | 2. Check if image is present (protodb/protofire-solhint:latest)
8 | `docker images`
9 |
10 | 3. Solhint use:
11 |
12 | - Execute solhint with default config file
13 | `docker run -v ./:/app -w /app -it protodb/protofire-solhint solhint './contracts/*.sol'`
14 |
15 | This command:
16 | - Maps current folder to app/ inside container
17 | - Executes solhint in './contracts/*.sol'
18 |
19 | - Navigate inside container sharing current folder into app/ container folder
20 | `docker run -v ./:/app -w /app -it protodb/protofire-solhint /bin/sh`
21 |
22 | This command:
23 | - Maps current folder to app/ container folder
24 | - Can run solhint inside the container by typing `solhint ./contracts/*.sol`
25 | (use your correct path, type exit to finish)
26 |
--------------------------------------------------------------------------------
/docs/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-cayman
2 | gems:
3 | - jekyll-seo-tag
4 | - jekyll-sitemap
5 | defaults:
6 | - scope:
7 | path: index
8 | type: default
9 | values:
10 | layout: default
--------------------------------------------------------------------------------
/docs/_includes/head.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Solhint - Solidity Linter
4 |
5 |
6 |
7 |
8 |
9 | {% seo %}
10 |
11 |
--------------------------------------------------------------------------------
/docs/_includes/page-footer.html:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/docs/_includes/page-header.html:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/docs/_layouts/default.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {% include head.html %}
5 |
6 |
7 | {% include page-header.html %}
8 |
9 |
10 |
11 | {{ content }}
12 |
13 | {% include page-footer.html %}
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/docs/rules/best-practices/constructor-syntax.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "constructor-syntax | Solhint"
5 | ---
6 |
7 | # constructor-syntax
8 | 
9 | 
10 |
11 | ## Description
12 | Constructors should use the new constructor keyword.
13 |
14 | ## Options
15 | This rule accepts a string option for rule severity. Must be one of "error", "warn", "off". Defaults to warn.
16 |
17 | ### Example Config
18 | ```json
19 | {
20 | "rules": {
21 | "constructor-syntax": "warn"
22 | }
23 | }
24 | ```
25 |
26 |
27 | ## Examples
28 | This rule does not have examples.
29 |
30 | ## Version
31 | This rule was introduced in [Solhint 1.2.0](https://github.com/protofire/solhint/blob/v1.2.0)
32 |
33 | ## Resources
34 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/deprecations/constructor-syntax.js)
35 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/deprecations/constructor-syntax.md)
36 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/deprecations/constructor-syntax.js)
37 |
--------------------------------------------------------------------------------
/docs/rules/best-practices/function-max-lines.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "function-max-lines | Solhint"
5 | ---
6 |
7 | # function-max-lines
8 | 
9 | 
10 |
11 | ## Description
12 | Function body contains "count" lines but allowed no more than maxlines.
13 |
14 | ## Options
15 | This rule accepts an array of options:
16 |
17 | | Index | Description | Default Value |
18 | | ----- | ----------------------------------------------------- | ------------- |
19 | | 0 | Rule severity. Must be one of "error", "warn", "off". | warn |
20 | | 1 | Maximum allowed lines count per function | 50 |
21 |
22 |
23 | ### Example Config
24 | ```json
25 | {
26 | "rules": {
27 | "function-max-lines": ["warn",50]
28 | }
29 | }
30 | ```
31 |
32 |
33 | ## Examples
34 | This rule does not have examples.
35 |
36 | ## Version
37 | This rule was introduced in [Solhint 5.0.4](https://github.com/protofire/solhint/blob/v5.0.4)
38 |
39 | ## Resources
40 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/best-practices/function-max-lines.js)
41 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/best-practices/function-max-lines.md)
42 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/best-practices/function-max-lines.js)
43 |
--------------------------------------------------------------------------------
/docs/rules/best-practices/max-line-length.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "max-line-length | Solhint"
5 | ---
6 |
7 | # max-line-length
8 | 
9 | 
10 | > The {"extends": "solhint:default"} property in a configuration file enables this rule. THIS IS DEPRECATED SINCE VERSION 5.1.0
11 |
12 |
13 | ## Description
14 | Line length must be no more than maxlen.
15 |
16 | ## Options
17 | This rule accepts an array of options:
18 |
19 | | Index | Description | Default Value |
20 | | ----- | ----------------------------------------------------- | ------------- |
21 | | 0 | Rule severity. Must be one of "error", "warn", "off". | error |
22 | | 1 | Maximum allowed number of characters per line | 120 |
23 |
24 |
25 | ### Example Config
26 | ```json
27 | {
28 | "rules": {
29 | "max-line-length": ["error",120]
30 | }
31 | }
32 | ```
33 |
34 |
35 | ## Examples
36 | This rule does not have examples.
37 |
38 | ## Version
39 | This rule was introduced in [Solhint 5.0.4](https://github.com/protofire/solhint/blob/v5.0.4)
40 |
41 | ## Resources
42 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/best-practices/max-line-length.js)
43 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/best-practices/max-line-length.md)
44 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/best-practices/max-line-length.js)
45 |
--------------------------------------------------------------------------------
/docs/rules/best-practices/no-unused-vars.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "no-unused-vars | Solhint"
5 | ---
6 |
7 | # no-unused-vars
8 | 
9 | 
10 | 
11 | > The {"extends": "solhint:recommended"} property in a configuration file enables this rule.
12 |
13 |
14 | ## Description
15 | Variable "name" is unused.
16 |
17 | ## Options
18 | This rule accepts a string option for rule severity. Must be one of "error", "warn", "off". Defaults to warn.
19 |
20 | ### Example Config
21 | ```json
22 | {
23 | "rules": {
24 | "no-unused-vars": "warn"
25 | }
26 | }
27 | ```
28 |
29 |
30 | ## Examples
31 | This rule does not have examples.
32 |
33 | ## Version
34 | This rule was introduced in [Solhint 5.0.4](https://github.com/protofire/solhint/blob/v5.0.4)
35 |
36 | ## Resources
37 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/best-practices/no-unused-vars.js)
38 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/best-practices/no-unused-vars.md)
39 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/best-practices/no-unused-vars.js)
40 |
--------------------------------------------------------------------------------
/docs/rules/best-practices/one-contract-per-file.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "one-contract-per-file | Solhint"
5 | ---
6 |
7 | # one-contract-per-file
8 | 
9 | 
10 | 
11 | > The {"extends": "solhint:recommended"} property in a configuration file enables this rule.
12 |
13 |
14 | ## Description
15 | Enforces the use of ONE Contract per file see [here](https://docs.soliditylang.org/en/v0.8.21/style-guide.html#contract-and-library-names)
16 |
17 | ## Options
18 | This rule accepts a string option for rule severity. Must be one of "error", "warn", "off". Defaults to warn.
19 |
20 | ### Example Config
21 | ```json
22 | {
23 | "rules": {
24 | "one-contract-per-file": "warn"
25 | }
26 | }
27 | ```
28 |
29 |
30 | ## Examples
31 | This rule does not have examples.
32 |
33 | ## Version
34 | This rule was introduced in [Solhint 5.0.4](https://github.com/protofire/solhint/blob/v5.0.4)
35 |
36 | ## Resources
37 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/best-practices/one-contract-per-file.js)
38 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/best-practices/one-contract-per-file.md)
39 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/best-practices/one-contract-per-file.js)
40 |
--------------------------------------------------------------------------------
/docs/rules/gas-consumption/gas-indexed-events.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "gas-indexed-events | Solhint"
5 | ---
6 |
7 | # gas-indexed-events
8 | 
9 | 
10 |
11 | ## Description
12 | Suggest indexed arguments on events for uint, bool and address
13 |
14 | ## Options
15 | This rule accepts a string option for rule severity. Must be one of "error", "warn", "off". Defaults to warn.
16 |
17 | ### Example Config
18 | ```json
19 | {
20 | "rules": {
21 | "gas-indexed-events": "warn"
22 | }
23 | }
24 | ```
25 |
26 | ### Notes
27 | - [source](https://coinsbench.com/comprehensive-guide-tips-and-tricks-for-gas-optimization-in-solidity-5380db734404) of the rule initiative (see Indexed Events)
28 |
29 | ## Examples
30 | This rule does not have examples.
31 |
32 | ## Version
33 | This rule was introduced in [Solhint 4.5.0](https://github.com/protofire/solhint/blob/v4.5.0)
34 |
35 | ## Resources
36 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/gas-consumption/gas-indexed-events.js)
37 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/gas-consumption/gas-indexed-events.md)
38 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/gas-consumption/gas-indexed-events.js)
39 |
--------------------------------------------------------------------------------
/docs/rules/gas-consumption/gas-length-in-loops.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "gas-length-in-loops | Solhint"
5 | ---
6 |
7 | # gas-length-in-loops
8 | 
9 | 
10 |
11 | ## Description
12 | Suggest replacing object.length in a loop condition to avoid calculation on each lap
13 |
14 | ## Options
15 | This rule accepts a string option for rule severity. Must be one of "error", "warn", "off". Defaults to warn.
16 |
17 | ### Example Config
18 | ```json
19 | {
20 | "rules": {
21 | "gas-length-in-loops": "warn"
22 | }
23 | }
24 | ```
25 |
26 | ### Notes
27 | - [source 1](https://coinsbench.com/comprehensive-guide-tips-and-tricks-for-gas-optimization-in-solidity-5380db734404) of the rule initiative (see Array Length Caching)
28 |
29 | ## Examples
30 | This rule does not have examples.
31 |
32 | ## Version
33 | This rule was introduced in [Solhint 4.5.0](https://github.com/protofire/solhint/blob/v4.5.0)
34 |
35 | ## Resources
36 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/gas-consumption/gas-length-in-loops.js)
37 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/gas-consumption/gas-length-in-loops.md)
38 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/gas-consumption/gas-length-in-loops.js)
39 |
--------------------------------------------------------------------------------
/docs/rules/gas-consumption/gas-multitoken1155.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "gas-multitoken1155 | Solhint"
5 | ---
6 |
7 | # gas-multitoken1155
8 | 
9 | 
10 |
11 | ## Description
12 | ERC1155 is a cheaper non-fungible token than ERC721
13 |
14 | ## Options
15 | This rule accepts a string option for rule severity. Must be one of "error", "warn", "off". Defaults to warn.
16 |
17 | ### Example Config
18 | ```json
19 | {
20 | "rules": {
21 | "gas-multitoken1155": "warn"
22 | }
23 | }
24 | ```
25 |
26 | ### Notes
27 | - [source](https://www.rareskills.io/post/gas-optimization?postId=c9db474a-ff97-4fa3-a51d-fe13ccb8fe3b#viewer-8v8t9) of the rule initiative
28 |
29 | ## Examples
30 | This rule does not have examples.
31 |
32 | ## Version
33 | This rule was introduced in [Solhint 4.5.0](https://github.com/protofire/solhint/blob/v4.5.0)
34 |
35 | ## Resources
36 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/gas-consumption/gas-multitoken1155.js)
37 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/gas-consumption/gas-multitoken1155.md)
38 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/gas-consumption/gas-multitoken1155.js)
39 |
--------------------------------------------------------------------------------
/docs/rules/gas-consumption/gas-small-strings.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "gas-small-strings | Solhint"
5 | ---
6 |
7 | # gas-small-strings
8 | 
9 | 
10 |
11 | ## Description
12 | Keep strings smaller than 32 bytes
13 |
14 | ## Options
15 | This rule accepts a string option for rule severity. Must be one of "error", "warn", "off". Defaults to warn.
16 |
17 | ### Example Config
18 | ```json
19 | {
20 | "rules": {
21 | "gas-small-strings": "warn"
22 | }
23 | }
24 | ```
25 |
26 | ### Notes
27 | - [source](https://www.rareskills.io/post/gas-optimization?postId=c9db474a-ff97-4fa3-a51d-fe13ccb8fe3b#viewer-ck1vq) of the rule initiative
28 |
29 | ## Examples
30 | This rule does not have examples.
31 |
32 | ## Version
33 | This rule was introduced in [Solhint 4.5.0](https://github.com/protofire/solhint/blob/v4.5.0)
34 |
35 | ## Resources
36 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/gas-consumption/gas-small-strings.js)
37 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/gas-consumption/gas-small-strings.md)
38 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/gas-consumption/gas-small-strings.js)
39 |
--------------------------------------------------------------------------------
/docs/rules/naming/const-name-snakecase.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "const-name-snakecase | Solhint"
5 | ---
6 |
7 | # const-name-snakecase
8 | 
9 | 
10 | 
11 | > The {"extends": "solhint:recommended"} property in a configuration file enables this rule.
12 |
13 |
14 | ## Description
15 | Constant name must be in capitalized SNAKE_CASE. (Does not check IMMUTABLES, use immutable-vars-naming)
16 |
17 | ## Options
18 | This rule accepts a string option for rule severity. Must be one of "error", "warn", "off". Defaults to warn.
19 |
20 | ### Example Config
21 | ```json
22 | {
23 | "rules": {
24 | "const-name-snakecase": "warn"
25 | }
26 | }
27 | ```
28 |
29 |
30 | ## Examples
31 | This rule does not have examples.
32 |
33 | ## Version
34 | This rule was introduced in [Solhint 2.0.0-alpha.0](https://github.com/protofire/solhint/blob/v2.0.0-alpha.0)
35 |
36 | ## Resources
37 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/naming/const-name-snakecase.js)
38 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/naming/const-name-snakecase.md)
39 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/naming/const-name-snakecase.js)
40 |
--------------------------------------------------------------------------------
/docs/rules/naming/contract-name-camelcase.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "contract-name-camelcase | Solhint"
5 | ---
6 |
7 | # contract-name-camelcase
8 | 
9 | 
10 | 
11 | > The {"extends": "solhint:recommended"} property in a configuration file enables this rule.
12 |
13 |
14 | ## Description
15 | Contract, Structs and Enums should be in CamelCase.
16 |
17 | ## Options
18 | This rule accepts a string option of rule severity. Must be one of "error", "warn", "off". Defaults to warn.
19 |
20 | ### Example Config
21 | ```json
22 | {
23 | "rules": {
24 | "contract-name-camelcase": "warn"
25 | }
26 | }
27 | ```
28 |
29 | ### Notes
30 | - Solhint allows this rule to automatically fix the code with `--fix` option
31 | - The FIX will only change first letter and remove underscores
32 |
33 | ## Examples
34 | This rule does not have examples.
35 |
36 | ## Version
37 | This rule was introduced in [Solhint 2.0.0-alpha.0](https://github.com/protofire/solhint/blob/v2.0.0-alpha.0)
38 |
39 | ## Resources
40 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/naming/contract-name-camelcase.js)
41 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/naming/contract-name-camelcase.md)
42 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/naming/contract-name-camelcase.js)
43 |
--------------------------------------------------------------------------------
/docs/rules/naming/contract-name-capwords.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "contract-name-capwords | Solhint"
5 | ---
6 |
7 | # contract-name-capwords
8 | 
9 | 
10 | 
11 | > The {"extends": "solhint:recommended"} property in a configuration file enables this rule.
12 |
13 |
14 | ## Description
15 | Contract, Structs and Enums should be in CapWords.
16 |
17 | ## Options
18 | This rule accepts a string option for rule severity. Must be one of "error", "warn", "off". Defaults to warn.
19 |
20 | ### Example Config
21 | ```json
22 | {
23 | "rules": {
24 | "contract-name-capwords": "warn"
25 | }
26 | }
27 | ```
28 |
29 | ### Notes
30 | - Solhint allows this rule to automatically fix the code with `--fix` option
31 | - The FIX will only change first letter and remove underscores
32 |
33 | ## Examples
34 | This rule does not have examples.
35 |
36 | ## Version
37 | This rule was introduced in [Solhint 5.0.4](https://github.com/protofire/solhint/blob/v5.0.4)
38 |
39 | ## Resources
40 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/naming/contract-name-capwords.js)
41 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/naming/contract-name-capwords.md)
42 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/naming/contract-name-capwords.js)
43 |
--------------------------------------------------------------------------------
/docs/rules/naming/event-name-camelcase.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "event-name-camelcase | Solhint"
5 | ---
6 |
7 | # event-name-camelcase
8 | 
9 | 
10 | 
11 | > The {"extends": "solhint:recommended"} property in a configuration file enables this rule.
12 |
13 |
14 | ## Description
15 | Event name must be in CamelCase.
16 |
17 | ## Options
18 | This rule accepts a string option of rule severity. Must be one of "error", "warn", "off". Defaults to warn.
19 |
20 | ### Example Config
21 | ```json
22 | {
23 | "rules": {
24 | "event-name-camelcase": "warn"
25 | }
26 | }
27 | ```
28 |
29 | ### Notes
30 | - Solhint allows this rule to automatically fix the code with `--fix` option
31 | - The FIX will only change first letter and remove underscores
32 |
33 | ## Examples
34 | This rule does not have examples.
35 |
36 | ## Version
37 | This rule was introduced in [Solhint 2.0.0-alpha.0](https://github.com/protofire/solhint/blob/v2.0.0-alpha.0)
38 |
39 | ## Resources
40 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/naming/event-name-camelcase.js)
41 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/naming/event-name-camelcase.md)
42 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/naming/event-name-camelcase.js)
43 |
--------------------------------------------------------------------------------
/docs/rules/naming/event-name-capwords.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "event-name-capwords | Solhint"
5 | ---
6 |
7 | # event-name-capwords
8 | 
9 | 
10 | 
11 | > The {"extends": "solhint:recommended"} property in a configuration file enables this rule.
12 |
13 |
14 | ## Description
15 | Event name must be in CapWords.
16 |
17 | ## Options
18 | This rule accepts a string option for rule severity. Must be one of "error", "warn", "off". Defaults to warn.
19 |
20 | ### Example Config
21 | ```json
22 | {
23 | "rules": {
24 | "event-name-capwords": "warn"
25 | }
26 | }
27 | ```
28 |
29 | ### Notes
30 | - Solhint allows this rule to automatically fix the code with `--fix` option
31 | - The FIX will only change first letter and remove underscores
32 |
33 | ## Examples
34 | This rule does not have examples.
35 |
36 | ## Version
37 | This rule was introduced in [Solhint 5.0.4](https://github.com/protofire/solhint/blob/v5.0.4)
38 |
39 | ## Resources
40 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/naming/event-name-capwords.js)
41 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/naming/event-name-capwords.md)
42 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/naming/event-name-capwords.js)
43 |
--------------------------------------------------------------------------------
/docs/rules/naming/event-name-pascalcase.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "event-name-pascalcase | Solhint"
5 | ---
6 |
7 | # event-name-pascalcase
8 | 
9 | 
10 | 
11 | > The {"extends": "solhint:recommended"} property in a configuration file enables this rule.
12 |
13 |
14 | ## Description
15 | Event name must be in PascalCase.
16 |
17 | ## Options
18 | This rule accepts a string option of rule severity. Must be one of "error", "warn", "off". Defaults to warn.
19 |
20 | ### Example Config
21 | ```json
22 | {
23 | "rules": {
24 | "event-name-pascalcase": "warn"
25 | }
26 | }
27 | ```
28 |
29 | ### Notes
30 | - Solhint allows this rule to automatically fix the code with `--fix` option
31 | - The FIX will only change first letter and remove underscores
32 |
33 | ## Examples
34 | This rule does not have examples.
35 |
36 | ## Version
37 | This rule is introduced in the latest version.
38 |
39 | ## Resources
40 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/naming/event-name-pascalcase.js)
41 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/naming/event-name-pascalcase.md)
42 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/naming/event-name-pascalcase.js)
43 |
--------------------------------------------------------------------------------
/docs/rules/naming/func-name-mixedcase.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "func-name-mixedcase | Solhint"
5 | ---
6 |
7 | # func-name-mixedcase
8 | 
9 | 
10 | 
11 | > The {"extends": "solhint:recommended"} property in a configuration file enables this rule.
12 |
13 |
14 | ## Description
15 | Function name must be in mixedCase.
16 |
17 | ## Options
18 | This rule accepts a string option for rule severity. Must be one of "error", "warn", "off". Defaults to warn.
19 |
20 | ### Example Config
21 | ```json
22 | {
23 | "rules": {
24 | "func-name-mixedcase": "warn"
25 | }
26 | }
27 | ```
28 |
29 |
30 | ## Examples
31 | This rule does not have examples.
32 |
33 | ## Version
34 | This rule was introduced in [Solhint 2.0.0-alpha.0](https://github.com/protofire/solhint/blob/v2.0.0-alpha.0)
35 |
36 | ## Resources
37 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/naming/func-name-mixedcase.js)
38 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/naming/func-name-mixedcase.md)
39 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/naming/func-name-mixedcase.js)
40 |
--------------------------------------------------------------------------------
/docs/rules/naming/func-param-name-mixedcase.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "func-param-name-mixedcase | Solhint"
5 | ---
6 |
7 | # func-param-name-mixedcase
8 | 
9 | 
10 |
11 | ## Description
12 | Function param name must be in mixedCase.
13 |
14 | ## Options
15 | This rule accepts a string option for rule severity. Must be one of "error", "warn", "off". Defaults to warn.
16 |
17 | ### Example Config
18 | ```json
19 | {
20 | "rules": {
21 | "func-param-name-mixedcase": "warn"
22 | }
23 | }
24 | ```
25 |
26 |
27 | ## Examples
28 | This rule does not have examples.
29 |
30 | ## Version
31 | This rule was introduced in [Solhint 2.0.0-alpha.0](https://github.com/protofire/solhint/blob/v2.0.0-alpha.0)
32 |
33 | ## Resources
34 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/naming/func-param-name-mixedcase.js)
35 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/naming/func-param-name-mixedcase.md)
36 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/naming/func-param-name-mixedcase.js)
37 |
--------------------------------------------------------------------------------
/docs/rules/naming/interface-starts-with-i.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "interface-starts-with-i | Solhint"
5 | ---
6 |
7 | # interface-starts-with-i
8 | 
9 | 
10 |
11 | ## Description
12 | Solidity Interfaces names should start with an `I`
13 |
14 | ## Options
15 | This rule accepts a string option for rule severity. Must be one of "error", "warn", "off". Defaults to warn.
16 |
17 | ### Example Config
18 | ```json
19 | {
20 | "rules": {
21 | "interface-starts-with-i": "warn"
22 | }
23 | }
24 | ```
25 |
26 |
27 | ## Examples
28 | ### 👍 Examples of **correct** code for this rule
29 |
30 | #### Interface name starts with I
31 |
32 | ```solidity
33 | interface IFoo { function foo () external; }
34 | ```
35 |
36 | ### 👎 Examples of **incorrect** code for this rule
37 |
38 | #### Interface name doesn't start with I
39 |
40 | ```solidity
41 | interface Foo { function foo () external; }
42 | ```
43 |
44 | ## Version
45 | This rule was introduced in [Solhint 5.0.4](https://github.com/protofire/solhint/blob/v5.0.4)
46 |
47 | ## Resources
48 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/best-practices/interface-starts-with-i.js)
49 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/best-practices/interface-starts-with-i.md)
50 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/best-practices/interface-starts-with-i.js)
51 |
--------------------------------------------------------------------------------
/docs/rules/naming/modifier-name-mixedcase.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "modifier-name-mixedcase | Solhint"
5 | ---
6 |
7 | # modifier-name-mixedcase
8 | 
9 | 
10 |
11 | ## Description
12 | Modifier name must be in mixedCase.
13 |
14 | ## Options
15 | This rule accepts a string option for rule severity. Must be one of "error", "warn", "off". Defaults to warn.
16 |
17 | ### Example Config
18 | ```json
19 | {
20 | "rules": {
21 | "modifier-name-mixedcase": "warn"
22 | }
23 | }
24 | ```
25 |
26 |
27 | ## Examples
28 | This rule does not have examples.
29 |
30 | ## Version
31 | This rule was introduced in [Solhint 2.0.0-alpha.0](https://github.com/protofire/solhint/blob/v2.0.0-alpha.0)
32 |
33 | ## Resources
34 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/naming/modifier-name-mixedcase.js)
35 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/naming/modifier-name-mixedcase.md)
36 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/naming/modifier-name-mixedcase.js)
37 |
--------------------------------------------------------------------------------
/docs/rules/naming/use-forbidden-name.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "use-forbidden-name | Solhint"
5 | ---
6 |
7 | # use-forbidden-name
8 | 
9 | 
10 | 
11 | > The {"extends": "solhint:recommended"} property in a configuration file enables this rule.
12 |
13 |
14 | ## Description
15 | Avoid to use letters 'I', 'l', 'O' as identifiers.
16 |
17 | ## Options
18 | This rule accepts a string option for rule severity. Must be one of "error", "warn", "off". Defaults to warn.
19 |
20 | ### Example Config
21 | ```json
22 | {
23 | "rules": {
24 | "use-forbidden-name": "warn"
25 | }
26 | }
27 | ```
28 |
29 |
30 | ## Examples
31 | This rule does not have examples.
32 |
33 | ## Version
34 | This rule was introduced in [Solhint 2.0.0-alpha.0](https://github.com/protofire/solhint/blob/v2.0.0-alpha.0)
35 |
36 | ## Resources
37 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/naming/use-forbidden-name.js)
38 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/naming/use-forbidden-name.md)
39 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/naming/use-forbidden-name.js)
40 |
--------------------------------------------------------------------------------
/docs/rules/naming/var-name-mixedcase.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "var-name-mixedcase | Solhint"
5 | ---
6 |
7 | # var-name-mixedcase
8 | 
9 | 
10 | 
11 | > The {"extends": "solhint:recommended"} property in a configuration file enables this rule.
12 |
13 |
14 | ## Description
15 | Variable names must be in mixedCase. (Does not check IMMUTABLES, use immutable-vars-naming)
16 |
17 | ## Options
18 | This rule accepts a string option for rule severity. Must be one of "error", "warn", "off". Defaults to warn.
19 |
20 | ### Example Config
21 | ```json
22 | {
23 | "rules": {
24 | "var-name-mixedcase": "warn"
25 | }
26 | }
27 | ```
28 |
29 |
30 | ## Examples
31 | This rule does not have examples.
32 |
33 | ## Version
34 | This rule was introduced in [Solhint 2.0.0-alpha.0](https://github.com/protofire/solhint/blob/v2.0.0-alpha.0)
35 |
36 | ## Resources
37 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/naming/var-name-mixedcase.js)
38 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/naming/var-name-mixedcase.md)
39 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/naming/var-name-mixedcase.js)
40 |
--------------------------------------------------------------------------------
/docs/rules/order/imports-on-top.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "imports-on-top | Solhint"
5 | ---
6 |
7 | # imports-on-top
8 | 
9 | 
10 | 
11 | > The {"extends": "solhint:recommended"} property in a configuration file enables this rule.
12 |
13 |
14 | ## Description
15 | Import statements must be on top.
16 |
17 | ## Options
18 | This rule accepts a string option for rule severity. Must be one of "error", "warn", "off". Defaults to warn.
19 |
20 | ### Example Config
21 | ```json
22 | {
23 | "rules": {
24 | "imports-on-top": "warn"
25 | }
26 | }
27 | ```
28 |
29 |
30 | ## Examples
31 | This rule does not have examples.
32 |
33 | ## Version
34 | This rule was introduced in [Solhint 1.1.5](https://github.com/protofire/solhint/blob/v1.1.5)
35 |
36 | ## Resources
37 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/order/imports-on-top.js)
38 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/order/imports-on-top.md)
39 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/order/imports-on-top.js)
40 |
--------------------------------------------------------------------------------
/docs/rules/security/avoid-call-value.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "avoid-call-value | Solhint"
5 | ---
6 |
7 | # avoid-call-value
8 | 
9 | 
10 | 
11 | > The {"extends": "solhint:recommended"} property in a configuration file enables this rule.
12 |
13 |
14 | ## Description
15 | Avoid to use ".call.value()()".
16 |
17 | ## Options
18 | This rule accepts a string option for rule severity. Must be one of "error", "warn", "off". Defaults to warn.
19 |
20 | ### Example Config
21 | ```json
22 | {
23 | "rules": {
24 | "avoid-call-value": "warn"
25 | }
26 | }
27 | ```
28 |
29 |
30 | ## Examples
31 | This rule does not have examples.
32 |
33 | ## Version
34 | This rule was introduced in [Solhint 2.0.0-alpha.0](https://github.com/protofire/solhint/blob/v2.0.0-alpha.0)
35 |
36 | ## Resources
37 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/security/avoid-call-value.js)
38 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/security/avoid-call-value.md)
39 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/security/avoid-call-value.js)
40 |
--------------------------------------------------------------------------------
/docs/rules/security/avoid-sha3.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "avoid-sha3 | Solhint"
5 | ---
6 |
7 | # avoid-sha3
8 | 
9 | 
10 | 
11 | > The {"extends": "solhint:recommended"} property in a configuration file enables this rule.
12 |
13 |
14 | ## Description
15 | Use "keccak256" instead of deprecated "sha3".
16 |
17 | ## Options
18 | This rule accepts a string option for rule severity. Must be one of "error", "warn", "off". Defaults to warn.
19 |
20 | ### Example Config
21 | ```json
22 | {
23 | "rules": {
24 | "avoid-sha3": "warn"
25 | }
26 | }
27 | ```
28 |
29 | ### Notes
30 | - Solhint allows this rule to automatically fix the code with `--fix` option
31 |
32 | ## Examples
33 | This rule does not have examples.
34 |
35 | ## Version
36 | This rule was introduced in [Solhint 2.0.0-alpha.0](https://github.com/protofire/solhint/blob/v2.0.0-alpha.0)
37 |
38 | ## Resources
39 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/security/avoid-sha3.js)
40 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/security/avoid-sha3.md)
41 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/security/avoid-sha3.js)
42 |
--------------------------------------------------------------------------------
/docs/rules/security/avoid-suicide.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "avoid-suicide | Solhint"
5 | ---
6 |
7 | # avoid-suicide
8 | 
9 | 
10 | 
11 | > The {"extends": "solhint:recommended"} property in a configuration file enables this rule.
12 |
13 |
14 | ## Description
15 | Use "selfdestruct" instead of deprecated "suicide".
16 |
17 | ## Options
18 | This rule accepts a string option for rule severity. Must be one of "error", "warn", "off". Defaults to warn.
19 |
20 | ### Example Config
21 | ```json
22 | {
23 | "rules": {
24 | "avoid-suicide": "warn"
25 | }
26 | }
27 | ```
28 |
29 |
30 | ## Examples
31 | This rule does not have examples.
32 |
33 | ## Version
34 | This rule was introduced in [Solhint 2.0.0-alpha.0](https://github.com/protofire/solhint/blob/v2.0.0-alpha.0)
35 |
36 | ## Resources
37 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/security/avoid-suicide.js)
38 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/security/avoid-suicide.md)
39 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/security/avoid-suicide.js)
40 |
--------------------------------------------------------------------------------
/docs/rules/security/avoid-throw.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "avoid-throw | Solhint"
5 | ---
6 |
7 | # avoid-throw
8 | 
9 | 
10 | 
11 | > The {"extends": "solhint:recommended"} property in a configuration file enables this rule.
12 |
13 |
14 | ## Description
15 | "throw" is deprecated, avoid to use it.
16 |
17 | ## Options
18 | This rule accepts a string option for rule severity. Must be one of "error", "warn", "off". Defaults to warn.
19 |
20 | ### Example Config
21 | ```json
22 | {
23 | "rules": {
24 | "avoid-throw": "warn"
25 | }
26 | }
27 | ```
28 |
29 | ### Notes
30 | - Solhint allows this rule to automatically fix the code with `--fix` option
31 |
32 | ## Examples
33 | This rule does not have examples.
34 |
35 | ## Version
36 | This rule was introduced in [Solhint 2.0.0-alpha.0](https://github.com/protofire/solhint/blob/v2.0.0-alpha.0)
37 |
38 | ## Resources
39 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/security/avoid-throw.js)
40 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/security/avoid-throw.md)
41 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/security/avoid-throw.js)
42 |
--------------------------------------------------------------------------------
/docs/rules/security/avoid-tx-origin.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "avoid-tx-origin | Solhint"
5 | ---
6 |
7 | # avoid-tx-origin
8 | 
9 | 
10 | 
11 | > The {"extends": "solhint:recommended"} property in a configuration file enables this rule.
12 |
13 |
14 | ## Description
15 | Avoid to use tx.origin.
16 |
17 | ## Options
18 | This rule accepts a string option for rule severity. Must be one of "error", "warn", "off". Defaults to warn.
19 |
20 | ### Example Config
21 | ```json
22 | {
23 | "rules": {
24 | "avoid-tx-origin": "warn"
25 | }
26 | }
27 | ```
28 |
29 |
30 | ## Examples
31 | This rule does not have examples.
32 |
33 | ## Version
34 | This rule was introduced in [Solhint 1.1.5](https://github.com/protofire/solhint/blob/v1.1.5)
35 |
36 | ## Resources
37 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/security/avoid-tx-origin.js)
38 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/security/avoid-tx-origin.md)
39 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/security/avoid-tx-origin.js)
40 |
--------------------------------------------------------------------------------
/docs/rules/security/compiler-version.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "compiler-version | Solhint"
5 | ---
6 |
7 | # compiler-version
8 | 
9 | 
10 | 
11 | > The {"extends": "solhint:recommended"} property in a configuration file enables this rule.
12 |
13 |
14 | ## Description
15 | Compiler version must satisfy a semver requirement.
16 |
17 | ## Options
18 | This rule accepts an array of options:
19 |
20 | | Index | Description | Default Value |
21 | | ----- | ----------------------------------------------------- | ------------- |
22 | | 0 | Rule severity. Must be one of "error", "warn", "off". | error |
23 | | 1 | Semver requirement | ^0.8.24 |
24 |
25 |
26 | ### Example Config
27 | ```json
28 | {
29 | "rules": {
30 | "compiler-version": ["error","^0.8.24"]
31 | }
32 | }
33 | ```
34 |
35 |
36 | ## Examples
37 | This rule does not have examples.
38 |
39 | ## Version
40 | This rule was introduced in [Solhint 2.1.0](https://github.com/protofire/solhint/blob/v2.1.0)
41 |
42 | ## Resources
43 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/security/compiler-version.js)
44 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/security/compiler-version.md)
45 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/security/compiler-version.js)
46 |
--------------------------------------------------------------------------------
/docs/rules/security/multiple-sends.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "multiple-sends | Solhint"
5 | ---
6 |
7 | # multiple-sends
8 | 
9 | 
10 | 
11 | > The {"extends": "solhint:recommended"} property in a configuration file enables this rule.
12 |
13 |
14 | ## Description
15 | Avoid multiple calls of "send" method in single transaction.
16 |
17 | ## Options
18 | This rule accepts a string option for rule severity. Must be one of "error", "warn", "off". Defaults to warn.
19 |
20 | ### Example Config
21 | ```json
22 | {
23 | "rules": {
24 | "multiple-sends": "warn"
25 | }
26 | }
27 | ```
28 |
29 |
30 | ## Examples
31 | This rule does not have examples.
32 |
33 | ## Version
34 | This rule was introduced in [Solhint 2.0.0-alpha.0](https://github.com/protofire/solhint/blob/v2.0.0-alpha.0)
35 |
36 | ## Resources
37 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/security/multiple-sends.js)
38 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/security/multiple-sends.md)
39 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/security/multiple-sends.js)
40 |
--------------------------------------------------------------------------------
/docs/rules/security/no-complex-fallback.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "no-complex-fallback | Solhint"
5 | ---
6 |
7 | # no-complex-fallback
8 | 
9 | 
10 | 
11 | > The {"extends": "solhint:recommended"} property in a configuration file enables this rule.
12 |
13 |
14 | ## Description
15 | Fallback function must be simple.
16 |
17 | ## Options
18 | This rule accepts a string option for rule severity. Must be one of "error", "warn", "off". Defaults to warn.
19 |
20 | ### Example Config
21 | ```json
22 | {
23 | "rules": {
24 | "no-complex-fallback": "warn"
25 | }
26 | }
27 | ```
28 |
29 |
30 | ## Examples
31 | This rule does not have examples.
32 |
33 | ## Version
34 | This rule was introduced in [Solhint 2.0.0-alpha.0](https://github.com/protofire/solhint/blob/v2.0.0-alpha.0)
35 |
36 | ## Resources
37 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/security/no-complex-fallback.js)
38 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/security/no-complex-fallback.md)
39 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/security/no-complex-fallback.js)
40 |
--------------------------------------------------------------------------------
/docs/rules/security/no-inline-assembly.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "no-inline-assembly | Solhint"
5 | ---
6 |
7 | # no-inline-assembly
8 | 
9 | 
10 | 
11 | > The {"extends": "solhint:recommended"} property in a configuration file enables this rule.
12 |
13 |
14 | ## Description
15 | Avoid to use inline assembly. It is acceptable only in rare cases.
16 |
17 | ## Options
18 | This rule accepts a string option for rule severity. Must be one of "error", "warn", "off". Defaults to warn.
19 |
20 | ### Example Config
21 | ```json
22 | {
23 | "rules": {
24 | "no-inline-assembly": "warn"
25 | }
26 | }
27 | ```
28 |
29 |
30 | ## Examples
31 | This rule does not have examples.
32 |
33 | ## Version
34 | This rule was introduced in [Solhint 1.1.6](https://github.com/protofire/solhint/blob/v1.1.6)
35 |
36 | ## Resources
37 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/security/no-inline-assembly.js)
38 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/security/no-inline-assembly.md)
39 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/security/no-inline-assembly.js)
40 |
--------------------------------------------------------------------------------
/docs/rules/security/not-rely-on-block-hash.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "not-rely-on-block-hash | Solhint"
5 | ---
6 |
7 | # not-rely-on-block-hash
8 | 
9 | 
10 | 
11 | > The {"extends": "solhint:recommended"} property in a configuration file enables this rule.
12 |
13 |
14 | ## Description
15 | Do not rely on "block.blockhash". Miners can influence its value.
16 |
17 | ## Options
18 | This rule accepts a string option for rule severity. Must be one of "error", "warn", "off". Defaults to warn.
19 |
20 | ### Example Config
21 | ```json
22 | {
23 | "rules": {
24 | "not-rely-on-block-hash": "warn"
25 | }
26 | }
27 | ```
28 |
29 |
30 | ## Examples
31 | This rule does not have examples.
32 |
33 | ## Version
34 | This rule was introduced in [Solhint 1.1.6](https://github.com/protofire/solhint/blob/v1.1.6)
35 |
36 | ## Resources
37 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/security/not-rely-on-block-hash.js)
38 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/security/not-rely-on-block-hash.md)
39 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/security/not-rely-on-block-hash.js)
40 |
--------------------------------------------------------------------------------
/docs/rules/security/not-rely-on-time.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "not-rely-on-time | Solhint"
5 | ---
6 |
7 | # not-rely-on-time
8 | 
9 | 
10 |
11 | ## Description
12 | Avoid making time-based decisions in your business logic.
13 |
14 | ## Options
15 | This rule accepts a string option for rule severity. Must be one of "error", "warn", "off". Defaults to warn.
16 |
17 | ### Example Config
18 | ```json
19 | {
20 | "rules": {
21 | "not-rely-on-time": "warn"
22 | }
23 | }
24 | ```
25 |
26 |
27 | ## Examples
28 | This rule does not have examples.
29 |
30 | ## Version
31 | This rule was introduced in [Solhint 1.1.5](https://github.com/protofire/solhint/blob/v1.1.5)
32 |
33 | ## Resources
34 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/security/not-rely-on-time.js)
35 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/security/not-rely-on-time.md)
36 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/security/not-rely-on-time.js)
37 |
--------------------------------------------------------------------------------
/docs/rules/security/state-visibility.md:
--------------------------------------------------------------------------------
1 | ---
2 | warning: "This is a dynamically generated file. Do not edit manually."
3 | layout: "default"
4 | title: "state-visibility | Solhint"
5 | ---
6 |
7 | # state-visibility
8 | 
9 | 
10 | 
11 | > The {"extends": "solhint:recommended"} property in a configuration file enables this rule.
12 |
13 |
14 | ## Description
15 | Explicitly mark visibility of state.
16 |
17 | ## Options
18 | This rule accepts a string option for rule severity. Must be one of "error", "warn", "off". Defaults to warn.
19 |
20 | ### Example Config
21 | ```json
22 | {
23 | "rules": {
24 | "state-visibility": "warn"
25 | }
26 | }
27 | ```
28 |
29 |
30 | ## Examples
31 | This rule does not have examples.
32 |
33 | ## Version
34 | This rule was introduced in [Solhint 2.0.0-alpha.0](https://github.com/protofire/solhint/blob/v2.0.0-alpha.0)
35 |
36 | ## Resources
37 | - [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/security/state-visibility.js)
38 | - [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/security/state-visibility.md)
39 | - [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/security/state-visibility.js)
40 |
--------------------------------------------------------------------------------
/docs/shareable-configs.md:
--------------------------------------------------------------------------------
1 | # Shareable Configs
2 |
3 | Shareable configs are configurations that you can use and extend from. They can be useful for using the same base configuration in all your projects or for basing your configuration from a well-known one.
4 |
5 | To use a shareable config, you have to add it to your Solhint configuration:
6 |
7 | ```
8 | "extends": ["solhint:recommended", "protofire"]
9 | ```
10 |
11 | This example shows the two types of shareable configs that you can use: the ones included with Solhint, that start with `solhint:`, and the ones that you can install from npm. The latter are packages that are prefixed with `solhint-config-`, so in this case the package would be installed doing `npm install solhint-config-protofire` but used as just `protofire` when adding it.
12 |
13 | ## Creating your own shareable config
14 |
15 | Shareable configs are regular npm packages. There are only two conditions:
16 |
17 | - The name of the package must start with `solhint-config-`
18 | - The package must export a regular object with the same structure as a regular configuration object (i.e. the one in your `.solhint.json`).
19 |
20 | For example, a very minimal `index.js` in this package could be:
21 |
22 | ```javascript
23 | module.exports = {
24 | rules: {
25 | 'max-line-length': 80
26 | }
27 | }
28 | ```
29 |
30 | After creating this package you can publish it to npm to make it available for everyone.
31 |
--------------------------------------------------------------------------------
/e2e/01-no-config/Foo.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.0;
2 |
3 | contract Foo {
4 | }
5 |
--------------------------------------------------------------------------------
/e2e/02-empty-solhint-json/.solhint.json:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/e2e/02-empty-solhint-json/Foo.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.0;
2 |
3 | contract Foo {
4 | }
5 |
--------------------------------------------------------------------------------
/e2e/03-no-empty-blocks/.solhint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "no-empty-blocks": "error",
4 | "compiler-version": "off"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/e2e/03-no-empty-blocks/Foo.sol:
--------------------------------------------------------------------------------
1 | pragma solidity >=0.5.0;
2 |
3 | contract Foo {
4 | }
5 |
--------------------------------------------------------------------------------
/e2e/04-dotSol-on-path/.solhint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "no-empty-blocks": "off",
4 | "compiler-version": "off"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/e2e/04-dotSol-on-path/contracts/ERC20.sol/ERC20.dbg.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/protofire/solhint/4dd80890cff0d00051f67f8133877f26482588bb/e2e/04-dotSol-on-path/contracts/ERC20.sol/ERC20.dbg.js
--------------------------------------------------------------------------------
/e2e/04-dotSol-on-path/contracts/ERC20.sol/Foo.sol:
--------------------------------------------------------------------------------
1 | pragma solidity >=0.5.0;
2 |
3 | contract Foo {
4 | }
5 |
--------------------------------------------------------------------------------
/e2e/05-max-warnings/.solhint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "solhint:all"
3 | }
4 |
--------------------------------------------------------------------------------
/e2e/05-max-warnings/contracts/Foo.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.8.24;
3 |
4 | contract Foo {
5 | uint256 public constant test1 = 1;
6 | uint256 TEST2;
7 |
8 | constructor() {
9 |
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/e2e/05-max-warnings/contracts/Foo2.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.6.0;
3 |
4 | contract Foo {
5 | uint256 public constant test1 = 1;
6 | uint256 TEST2;
7 |
8 | constructor() {}
9 |
10 | function TEST() {}
11 |
12 | modifier ZAR_tok() {}
13 |
14 | uint256 SOSO;
15 | }
16 |
--------------------------------------------------------------------------------
/e2e/06-formatters/.solhint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "solhint:all"
3 | }
4 |
--------------------------------------------------------------------------------
/e2e/06-formatters/contracts/Foo.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.6.0;
3 |
4 | contract Foo {
5 | uint256 public constant test1 = 1;
6 | uint256 TEST2;
7 |
8 | constructor() {
9 |
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/e2e/06-formatters/contracts/Foo2.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.8.24;
3 |
4 | contract Foo {
5 | uint256 public constant test1 = 1;
6 |
7 | constructor() {
8 |
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/e2e/06-formatters/contracts/Foo3.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.8.24;
3 |
4 | contract Foo {
5 | uint256 public constant TEST1 = 1;
6 | uint256 public value;
7 |
8 | function _goodContract() private {
9 | value = TEST1;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/e2e/07-foundry-test/.solhint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "solhint:recommended",
3 | "rules": {
4 | "compiler-version": "off",
5 | "func-visibility": "off"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/e2e/07-foundry-test/contracts/Foo.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.8.0;
3 |
4 | contract Foo {
5 | uint256 public constant TEST = 1;
6 |
7 | constructor() {
8 |
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/e2e/07-foundry-test/test/.solhint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "foundry-test-functions": ["error", ["setUp", "finish"]]
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/e2e/07-foundry-test/test/FooTest.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.6.0;
3 |
4 | import "./Test.sol";
5 |
6 | contract FooTest is Test {
7 | uint256 testNumber;
8 |
9 | function setUp() public {
10 | testNumber = 42;
11 | }
12 |
13 | function testFail_Subtract43() public {
14 | testNumber -= 43;
15 | }
16 |
17 | function wrongFunctionDefinitionName() public {
18 | testNumber -= 43;
19 | }
20 | }
--------------------------------------------------------------------------------
/e2e/07-foundry-test/test/Test.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.6.0;
3 |
4 | contract Test {}
5 |
--------------------------------------------------------------------------------
/e2e/08-autofix/_commands/.solhint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "explicit-types": ["error", "explicit"]
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/e2e/08-autofix/_commands/Foo1.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | pragma solidity ^0.8.24;
3 |
4 | import {ERC20Burnable} from '@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol';
5 |
6 | contract Foo1 is ERC20Burnable {
7 | uint public hola;
8 | uint public hola2;
9 | int public constant hola3 = 2;
10 | ufixed hola4;
11 | fixed internal hola5;
12 |
13 | constructor() ERC20('MyToken', 'MTK') {}
14 |
15 | // solhint-disable no-empty-blocks
16 | function payableTrue() public payable {}
17 |
18 | // solhint-disable no-empty-blocks
19 | function payableFalse() public {}
20 |
21 | function zarasa() {}
22 | }
23 |
--------------------------------------------------------------------------------
/e2e/08-autofix/_commands/Foo1AfterFix.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | pragma solidity ^0.8.24;
3 |
4 | import {ERC20Burnable} from '@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol';
5 |
6 | contract Foo1 is ERC20Burnable {
7 | uint256 public hola;
8 | uint256 public hola2;
9 | int256 public constant hola3 = 2;
10 | ufixed128x18 hola4;
11 | fixed128x18 internal hola5;
12 |
13 | constructor() ERC20('MyToken', 'MTK') {}
14 |
15 | // solhint-disable no-empty-blocks
16 | function payableTrue() public payable {}
17 |
18 | // solhint-disable no-empty-blocks
19 | function payableFalse() public {}
20 |
21 | function zarasa() {}
22 | }
23 |
--------------------------------------------------------------------------------
/e2e/08-autofix/_commands/Foo1BeforeFix.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | pragma solidity ^0.8.24;
3 |
4 | import {ERC20Burnable} from '@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol';
5 |
6 | contract Foo1 is ERC20Burnable {
7 | uint public hola;
8 | uint public hola2;
9 | int public constant hola3 = 2;
10 | ufixed hola4;
11 | fixed internal hola5;
12 |
13 | constructor() ERC20('MyToken', 'MTK') {}
14 |
15 | // solhint-disable no-empty-blocks
16 | function payableTrue() public payable {}
17 |
18 | // solhint-disable no-empty-blocks
19 | function payableFalse() public {}
20 |
21 | function zarasa() {}
22 | }
23 |
--------------------------------------------------------------------------------
/e2e/08-autofix/avoid-suicide/.solhint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "avoid-suicide": "error",
4 | "compiler-version": "off"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/e2e/08-autofix/avoid-suicide/Foo1.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | pragma solidity ^0.8.0;
3 |
4 | import '@openzeppelin/contracts/ownership/Suicide.sol';
5 | import { feature as suicide} from '@openzeppelin/contracts/ownership/Suicide.sol';
6 |
7 | uint256 constant suicide = 1;
8 |
9 | enum MyEnum {
10 | suicide,
11 | B
12 | }
13 |
14 | struct OneNiceStruct {
15 | uint256 suicide;
16 | uint256 b;
17 | }
18 |
19 | error Unauthorized();
20 |
21 | function freeFunction() pure returns (uint256) {
22 | suicide();
23 | return 1;
24 | }
25 |
26 | contract Generic {
27 | struct AnotherNiceStruct {
28 | uint256 suicide;
29 | uint256 c;
30 | }
31 |
32 | address constant owner = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
33 |
34 | function seekAndestroy1() external {
35 | suicide();
36 | }
37 |
38 | function seekAndestroy2() external {
39 | suicide(owner);
40 | }
41 |
42 | function seekAndestroy3() external {
43 | selfdestruct();
44 | }
45 |
46 | function seekAndestroy4() external {
47 | selfdestruct(owner);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/e2e/08-autofix/avoid-suicide/Foo1AfterFix.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | pragma solidity ^0.8.0;
3 |
4 | import '@openzeppelin/contracts/ownership/Suicide.sol';
5 | import { feature as suicide} from '@openzeppelin/contracts/ownership/Suicide.sol';
6 |
7 | uint256 constant suicide = 1;
8 |
9 | enum MyEnum {
10 | suicide,
11 | B
12 | }
13 |
14 | struct OneNiceStruct {
15 | uint256 suicide;
16 | uint256 b;
17 | }
18 |
19 | error Unauthorized();
20 |
21 | function freeFunction() pure returns (uint256) {
22 | selfdestruct();
23 | return 1;
24 | }
25 |
26 | contract Generic {
27 | struct AnotherNiceStruct {
28 | uint256 suicide;
29 | uint256 c;
30 | }
31 |
32 | address constant owner = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
33 |
34 | function seekAndestroy1() external {
35 | selfdestruct();
36 | }
37 |
38 | function seekAndestroy2() external {
39 | selfdestruct(owner);
40 | }
41 |
42 | function seekAndestroy3() external {
43 | selfdestruct();
44 | }
45 |
46 | function seekAndestroy4() external {
47 | selfdestruct(owner);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/e2e/08-autofix/avoid-suicide/Foo1BeforeFix.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | pragma solidity ^0.8.0;
3 |
4 | import '@openzeppelin/contracts/ownership/Suicide.sol';
5 | import { feature as suicide} from '@openzeppelin/contracts/ownership/Suicide.sol';
6 |
7 | uint256 constant suicide = 1;
8 |
9 | enum MyEnum {
10 | suicide,
11 | B
12 | }
13 |
14 | struct OneNiceStruct {
15 | uint256 suicide;
16 | uint256 b;
17 | }
18 |
19 | error Unauthorized();
20 |
21 | function freeFunction() pure returns (uint256) {
22 | suicide();
23 | return 1;
24 | }
25 |
26 | contract Generic {
27 | struct AnotherNiceStruct {
28 | uint256 suicide;
29 | uint256 c;
30 | }
31 |
32 | address constant owner = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
33 |
34 | function seekAndestroy1() external {
35 | suicide();
36 | }
37 |
38 | function seekAndestroy2() external {
39 | suicide(owner);
40 | }
41 |
42 | function seekAndestroy3() external {
43 | selfdestruct();
44 | }
45 |
46 | function seekAndestroy4() external {
47 | selfdestruct(owner);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/e2e/08-autofix/contract-name-capwords/.solhint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "contract-name-capwords": "error",
4 | "compiler-version": "off"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/e2e/08-autofix/contract-name-capwords/Foo1.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | pragma solidity ^0.8.0;
3 |
4 | struct not_Used_Struct1 {
5 | uint256 three;
6 | uint256 four;
7 | }
8 |
9 | enum __status1_ {
10 | Pending,
11 | Approved,
12 | Rejected
13 | }
14 |
15 | struct NotUsedStruct2 {
16 | uint256 three;
17 | uint256 four;
18 | }
19 |
20 | enum Status2 {
21 | Pending,
22 | Approved,
23 | Rejected
24 | }
25 |
26 | contract __generic {
27 |
28 | struct not_UsedStruct3__ {
29 | uint256 three;
30 | uint256 four;
31 | }
32 |
33 | enum status3 {
34 | Pending,
35 | Approved,
36 | Rejected
37 | }
38 |
39 | struct NotUsedStruct4 {
40 | uint256 three;
41 | uint256 four;
42 | }
43 |
44 | enum Status4 {
45 | Pending,
46 | Approved,
47 | Rejected
48 | }
49 |
50 | constructor() {}
51 |
52 | function function1() pure external {
53 | uint af1 = 0;
54 | af1;
55 | }
56 |
57 | function function2() external pure {
58 | uint b;
59 | b;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/e2e/08-autofix/contract-name-capwords/Foo1AfterFix.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | pragma solidity ^0.8.0;
3 |
4 | struct NotUsedStruct1 {
5 | uint256 three;
6 | uint256 four;
7 | }
8 |
9 | enum Status1 {
10 | Pending,
11 | Approved,
12 | Rejected
13 | }
14 |
15 | struct NotUsedStruct2 {
16 | uint256 three;
17 | uint256 four;
18 | }
19 |
20 | enum Status2 {
21 | Pending,
22 | Approved,
23 | Rejected
24 | }
25 |
26 | contract Generic {
27 |
28 | struct NotUsedStruct3 {
29 | uint256 three;
30 | uint256 four;
31 | }
32 |
33 | enum Status3 {
34 | Pending,
35 | Approved,
36 | Rejected
37 | }
38 |
39 | struct NotUsedStruct4 {
40 | uint256 three;
41 | uint256 four;
42 | }
43 |
44 | enum Status4 {
45 | Pending,
46 | Approved,
47 | Rejected
48 | }
49 |
50 | constructor() {}
51 |
52 | function function1() pure external {
53 | uint af1 = 0;
54 | af1;
55 | }
56 |
57 | function function2() external pure {
58 | uint b;
59 | b;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/e2e/08-autofix/contract-name-capwords/Foo1BeforeFix.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | pragma solidity ^0.8.0;
3 |
4 | struct not_Used_Struct1 {
5 | uint256 three;
6 | uint256 four;
7 | }
8 |
9 | enum __status1_ {
10 | Pending,
11 | Approved,
12 | Rejected
13 | }
14 |
15 | struct NotUsedStruct2 {
16 | uint256 three;
17 | uint256 four;
18 | }
19 |
20 | enum Status2 {
21 | Pending,
22 | Approved,
23 | Rejected
24 | }
25 |
26 | contract __generic {
27 |
28 | struct not_UsedStruct3__ {
29 | uint256 three;
30 | uint256 four;
31 | }
32 |
33 | enum status3 {
34 | Pending,
35 | Approved,
36 | Rejected
37 | }
38 |
39 | struct NotUsedStruct4 {
40 | uint256 three;
41 | uint256 four;
42 | }
43 |
44 | enum Status4 {
45 | Pending,
46 | Approved,
47 | Rejected
48 | }
49 |
50 | constructor() {}
51 |
52 | function function1() pure external {
53 | uint af1 = 0;
54 | af1;
55 | }
56 |
57 | function function2() external pure {
58 | uint b;
59 | b;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/e2e/08-autofix/event-name-capwords/.solhint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "event-name-capwords": "error",
4 | "compiler-version": "off"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/e2e/08-autofix/event-name-capwords/Foo1.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | pragma solidity ^0.8.0;
3 |
4 | contract Generic {
5 |
6 | event not_UsedEvent1(uint256 indexed amount, address account);
7 |
8 | event __not_UsedEvent___2(uint256 indexed amount, address indexed account);
9 |
10 | event not___UsedEvent3(uint256 amount, address account);
11 |
12 | event notUsedEvent4(uint256 indexed amount, address indexed account);
13 |
14 | event notUsedEvent5____(uint256 indexed amount, address account);
15 |
16 | event __not_UsedEvent6__(uint256 indexed amount, address account);
17 |
18 | event OkEvent1(uint256 indexed amount, address account);
19 |
20 | event OkEventOk2(uint256 indexed amount, address indexed account);
21 |
22 | constructor() {}
23 |
24 | function function1() external pure {
25 | uint af1 = 0;
26 | af1;
27 | }
28 |
29 | function function2() external pure {
30 | uint b;
31 | b;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/e2e/08-autofix/event-name-capwords/Foo1AfterFix.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | pragma solidity ^0.8.0;
3 |
4 | contract Generic {
5 |
6 | event NotUsedEvent1(uint256 indexed amount, address account);
7 |
8 | event NotUsedEvent2(uint256 indexed amount, address indexed account);
9 |
10 | event NotUsedEvent3(uint256 amount, address account);
11 |
12 | event NotUsedEvent4(uint256 indexed amount, address indexed account);
13 |
14 | event NotUsedEvent5(uint256 indexed amount, address account);
15 |
16 | event NotUsedEvent6(uint256 indexed amount, address account);
17 |
18 | event OkEvent1(uint256 indexed amount, address account);
19 |
20 | event OkEventOk2(uint256 indexed amount, address indexed account);
21 |
22 | constructor() {}
23 |
24 | function function1() external pure {
25 | uint af1 = 0;
26 | af1;
27 | }
28 |
29 | function function2() external pure {
30 | uint b;
31 | b;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/e2e/08-autofix/event-name-capwords/Foo1BeforeFix.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | pragma solidity ^0.8.0;
3 |
4 | contract Generic {
5 |
6 | event not_UsedEvent1(uint256 indexed amount, address account);
7 |
8 | event __not_UsedEvent___2(uint256 indexed amount, address indexed account);
9 |
10 | event not___UsedEvent3(uint256 amount, address account);
11 |
12 | event notUsedEvent4(uint256 indexed amount, address indexed account);
13 |
14 | event notUsedEvent5____(uint256 indexed amount, address account);
15 |
16 | event __not_UsedEvent6__(uint256 indexed amount, address account);
17 |
18 | event OkEvent1(uint256 indexed amount, address account);
19 |
20 | event OkEventOk2(uint256 indexed amount, address indexed account);
21 |
22 | constructor() {}
23 |
24 | function function1() external pure {
25 | uint af1 = 0;
26 | af1;
27 | }
28 |
29 | function function2() external pure {
30 | uint b;
31 | b;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/e2e/08-autofix/explicit-types/.solhint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "explicit-types": ["error", "explicit"],
4 | "compiler-version": "off"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/e2e/08-autofix/imports-order/.solhint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "imports-order": "error",
4 | "compiler-version": "off"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/e2e/08-autofix/imports-order/Foo1.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | pragma solidity ^0.8.0;
3 |
4 | import './ThisIsAVeryLongFileOnPurposeToTestTheFirstPathShorterThanTheLastOnelooooooooooong.sol';
5 | import { Unauthorized, add as func, Point } from './Foo.sol';
6 | import 'https://github.com/owner/repo/blob/branch/path/to/Contract.sol';
7 | import { Initializable } from './openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';
8 | import '../../../../token/interfaces/FakeContract1.sol';
9 | import { FakeContract3 } from '../../../token/interfaces/FakeContract3.sol';
10 | import './../../../../token/interfaces/AFakeContract1.sol';
11 | import './../token/interfaces/IXTokenWrapper.sol';
12 | import { IXTokenFactory, holaquetal } from '../../token/interfaces/IXTokenFactory.sol';
13 | import './../../bpath/otherfolder/otherfolder/aContract.sol';
14 | import '@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol';
15 | import { FakeContract2 } from '../../../token/interfaces/FakeContract2.sol';
16 | import '../../apath/zContract.sol';
17 | import 'http://github.com/owner/repo/blob/branch/path/to/Contract2.sol';
18 | import { Afool1 } from './Afool1.sol';
19 | import './Ownable.sol';
20 | import { IXTokenWrapper2 } from '../token/interfaces/IXTokenWrapper2.sol';
21 | import { ReentrancyGuardUpgradeable2 } from '@apenzeppelin/ReentrancyGuardUpgradeable2.sol';
22 |
23 | contract ImportsOrder {
24 | constructor() {}
25 | }
26 |
--------------------------------------------------------------------------------
/e2e/08-autofix/imports-order/Foo1AfterFix.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | pragma solidity ^0.8.0;
3 |
4 | import { ReentrancyGuardUpgradeable2 } from "@apenzeppelin/ReentrancyGuardUpgradeable2.sol";
5 | import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
6 | import "http://github.com/owner/repo/blob/branch/path/to/Contract2.sol";
7 | import "https://github.com/owner/repo/blob/branch/path/to/Contract.sol";
8 | import "./../../../../token/interfaces/AFakeContract1.sol";
9 | import "./../../../../token/interfaces/FakeContract1.sol";
10 | import { FakeContract2 } from "./../../../token/interfaces/FakeContract2.sol";
11 | import { FakeContract3 } from "./../../../token/interfaces/FakeContract3.sol";
12 | import "./../../apath/zContract.sol";
13 | import "./../../bpath/otherfolder/otherfolder/aContract.sol";
14 | import { IXTokenFactory, holaquetal } from "./../../token/interfaces/IXTokenFactory.sol";
15 | import "./../token/interfaces/IXTokenWrapper.sol";
16 | import { IXTokenWrapper2 } from "./../token/interfaces/IXTokenWrapper2.sol";
17 | import { Afool1 } from "./Afool1.sol";
18 | import { Unauthorized, add as func, Point } from "./Foo.sol";
19 | import { Initializable } from "./openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
20 | import "./Ownable.sol";
21 | import "./ThisIsAVeryLongFileOnPurposeToTestTheFirstPathShorterThanTheLastOnelooooooooooong.sol";
22 |
23 | contract ImportsOrder {
24 | constructor() {}
25 | }
26 |
--------------------------------------------------------------------------------
/e2e/08-autofix/imports-order/Foo1BeforeFix.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | pragma solidity ^0.8.0;
3 |
4 | import './ThisIsAVeryLongFileOnPurposeToTestTheFirstPathShorterThanTheLastOnelooooooooooong.sol';
5 | import { Unauthorized, add as func, Point } from './Foo.sol';
6 | import 'https://github.com/owner/repo/blob/branch/path/to/Contract.sol';
7 | import { Initializable } from './openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';
8 | import '../../../../token/interfaces/FakeContract1.sol';
9 | import { FakeContract3 } from '../../../token/interfaces/FakeContract3.sol';
10 | import './../../../../token/interfaces/AFakeContract1.sol';
11 | import './../token/interfaces/IXTokenWrapper.sol';
12 | import { IXTokenFactory, holaquetal } from '../../token/interfaces/IXTokenFactory.sol';
13 | import './../../bpath/otherfolder/otherfolder/aContract.sol';
14 | import '@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol';
15 | import { FakeContract2 } from '../../../token/interfaces/FakeContract2.sol';
16 | import '../../apath/zContract.sol';
17 | import 'http://github.com/owner/repo/blob/branch/path/to/Contract2.sol';
18 | import { Afool1 } from './Afool1.sol';
19 | import './Ownable.sol';
20 | import { IXTokenWrapper2 } from '../token/interfaces/IXTokenWrapper2.sol';
21 | import { ReentrancyGuardUpgradeable2 } from '@apenzeppelin/ReentrancyGuardUpgradeable2.sol';
22 |
23 | contract ImportsOrder {
24 | constructor() {}
25 | }
26 |
--------------------------------------------------------------------------------
/e2e/08-autofix/imports-order/Foo2.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | pragma solidity ^0.8.0;
3 |
4 | import './ThisIsAVeryLongFileOnPurposeToTestTheFirstPathShorterThanTheLastOnelooooooooooong.sol';
5 | import '../../../../../token/interfaces/IXTokenWrapper3.sol';
6 | import {IXTokenFactory2} from '../../atoken/interfaces/IXTokenFactory2.sol';
7 | import {Initializable} from './openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';
8 | import '../../../../token/interfaces/FakeContract1.sol';
9 | import '../token/interfaces/IXTokenWrapper.sol';
10 | import {IXTokenFactory, holaquetal} from '../../token/interfaces/IXTokenFactory.sol';
11 | import '@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol';
12 | import {FakeContract2} from '../../../token/interfaces/FakeContract2.sol';
13 | import {Afool1} from './Afool1.sol';
14 | import {IXTokenWrapper2} from '../token/interfaces/IXTokenWrapper2.sol';
15 | import {ReentrancyGuardUpgradeable2} from '@apenzeppelin/ReentrancyGuardUpgradeable2.sol';
16 |
17 | contract ImportsOrder2 {
18 | constructor() {}
19 | }
20 |
--------------------------------------------------------------------------------
/e2e/08-autofix/imports-order/Foo2AfterFix.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | pragma solidity ^0.8.0;
3 |
4 | import {ReentrancyGuardUpgradeable2} from '@apenzeppelin/ReentrancyGuardUpgradeable2.sol';
5 | import '@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol';
6 | import '../../../../../token/interfaces/IXTokenWrapper3.sol';
7 | import '../../../../token/interfaces/FakeContract1.sol';
8 | import {FakeContract2} from '../../../token/interfaces/FakeContract2.sol';
9 | import {IXTokenFactory2} from '../../atoken/interfaces/IXTokenFactory2.sol';
10 | import {IXTokenFactory, holaquetal} from '../../token/interfaces/IXTokenFactory.sol';
11 | import '../token/interfaces/IXTokenWrapper.sol';
12 | import {IXTokenWrapper2} from '../token/interfaces/IXTokenWrapper2.sol';
13 | import {Initializable} from './openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';
14 | import {Afool1} from './Afool1.sol';
15 | import './ThisIsAVeryLongFileOnPurposeToTestTheFirstPathShorterThanTheLastOnelooooooooooong.sol';
16 |
17 | contract ImportsOrder2 {
18 | constructor() {}
19 | }
20 |
--------------------------------------------------------------------------------
/e2e/08-autofix/imports-order/Foo2BeforeFix.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | pragma solidity ^0.8.0;
3 |
4 | import './ThisIsAVeryLongFileOnPurposeToTestTheFirstPathShorterThanTheLastOnelooooooooooong.sol';
5 | import '../../../../../token/interfaces/IXTokenWrapper3.sol';
6 | import {IXTokenFactory2} from '../../atoken/interfaces/IXTokenFactory2.sol';
7 | import {Initializable} from './openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';
8 | import '../../../../token/interfaces/FakeContract1.sol';
9 | import '../token/interfaces/IXTokenWrapper.sol';
10 | import {IXTokenFactory, holaquetal} from '../../token/interfaces/IXTokenFactory.sol';
11 | import '@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol';
12 | import {FakeContract2} from '../../../token/interfaces/FakeContract2.sol';
13 | import {Afool1} from './Afool1.sol';
14 | import {IXTokenWrapper2} from '../token/interfaces/IXTokenWrapper2.sol';
15 | import {ReentrancyGuardUpgradeable2} from '@apenzeppelin/ReentrancyGuardUpgradeable2.sol';
16 |
17 | contract ImportsOrder2 {
18 | constructor() {}
19 | }
20 |
--------------------------------------------------------------------------------
/e2e/08-autofix/no-console/.solhint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "no-console": "error",
4 | "compiler-version": "off"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/e2e/08-autofix/no-console/Foo1.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.8.0;
2 |
3 | import 'hardhat/console.sol';
4 | import 'forge-std/console.sol';
5 | import 'forge-std/console2.sol';
6 | import 'forge-std/xxxxx.sol';
7 |
8 | contract Foo1 {
9 | Console[] public consoleTest;
10 | Console[] public console;
11 |
12 | struct Console {
13 | uint256 one;
14 | uint256 two;
15 | }
16 |
17 | function a() public {
18 | console.log('test');
19 | // comment
20 | console.logString('test logString');
21 | uint256 declaration;
22 | console.logBytes12('test logBytes12');
23 | }
24 |
25 | function b() public {
26 | console2.log('test console 2');
27 | // comment
28 | console.logString('test logString');
29 | uint256 declaration;
30 | console.logBytes12('test');
31 | }
32 |
33 | function c() external {
34 | consoleTest.push(0, 0);
35 | console.push = (1, 1);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/e2e/08-autofix/no-console/Foo1AfterFix.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.8.0;
2 |
3 |
4 |
5 |
6 | import 'forge-std/xxxxx.sol';
7 |
8 | contract Foo1 {
9 | Console[] public consoleTest;
10 | Console[] public console;
11 |
12 | struct Console {
13 | uint256 one;
14 | uint256 two;
15 | }
16 |
17 | function a() public {
18 |
19 | // comment
20 |
21 | uint256 declaration;
22 |
23 | }
24 |
25 | function b() public {
26 |
27 | // comment
28 |
29 | uint256 declaration;
30 |
31 | }
32 |
33 | function c() external {
34 | consoleTest.push(0, 0);
35 | console.push = (1, 1);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/e2e/08-autofix/no-console/Foo1BeforeFix.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.8.0;
2 |
3 | import 'hardhat/console.sol';
4 | import 'forge-std/console.sol';
5 | import 'forge-std/console2.sol';
6 | import 'forge-std/xxxxx.sol';
7 |
8 | contract Foo1 {
9 | Console[] public consoleTest;
10 | Console[] public console;
11 |
12 | struct Console {
13 | uint256 one;
14 | uint256 two;
15 | }
16 |
17 | function a() public {
18 | console.log('test');
19 | // comment
20 | console.logString('test logString');
21 | uint256 declaration;
22 | console.logBytes12('test logBytes12');
23 | }
24 |
25 | function b() public {
26 | console2.log('test console 2');
27 | // comment
28 | console.logString('test logString');
29 | uint256 declaration;
30 | console.logBytes12('test');
31 | }
32 |
33 | function c() external {
34 | consoleTest.push(0, 0);
35 | console.push = (1, 1);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/e2e/08-autofix/no-unused-import/.solhint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "no-unused-import": "error",
4 | "compiler-version": "off"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/e2e/08-autofix/no-unused-import/Foo1.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | pragma solidity ^0.8.0;
3 |
4 | import { IERC20 } from '../token/interfaces/IERC20.sol';
5 | import { Bar, Civ, Zed as Nit } from '../Other.sol';
6 | import { Wyd, Abc as Mar } from '../Wyd.sol';
7 |
8 | contract Foo is Bar, Nit, Wyd {
9 | constructor() Bar() Nit(msg.sender) Wyd() {}
10 | }
11 |
--------------------------------------------------------------------------------
/e2e/08-autofix/no-unused-import/Foo1AfterFix.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | pragma solidity ^0.8.0;
3 |
4 | import { Bar, Zed as Nit } from '../Other.sol';
5 | import { Wyd } from '../Wyd.sol';
6 |
7 | contract Foo is Bar, Nit, Wyd {
8 | constructor() Bar() Nit(msg.sender) Wyd() {}
9 | }
10 |
--------------------------------------------------------------------------------
/e2e/08-autofix/no-unused-import/Foo1BeforeFix.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | pragma solidity ^0.8.0;
3 |
4 | import { IERC20 } from '../token/interfaces/IERC20.sol';
5 | import { Bar, Civ, Zed as Nit } from '../Other.sol';
6 | import { Wyd, Abc as Mar } from '../Wyd.sol';
7 |
8 | contract Foo is Bar, Nit, Wyd {
9 | constructor() Bar() Nit(msg.sender) Wyd() {}
10 | }
11 |
--------------------------------------------------------------------------------
/e2e/08-autofix/payable-fallback/.solhint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "payable-fallback": "error",
4 | "compiler-version": "off"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/e2e/08-autofix/payable-fallback/Foo1.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | pragma solidity ^0.8.0;
3 |
4 | contract FallbackNoReceive1 {
5 | constructor() {}
6 |
7 | function anyFunction() {}
8 |
9 | function() public {}
10 |
11 | function() {
12 | uint256 anUintToFillSpace;
13 | }
14 |
15 | function() external onlyOwner {}
16 |
17 | function() virtual {
18 | uint256 anUintToFillSpace;
19 | }
20 |
21 | //// fallback explicit
22 | fallback() external {}
23 |
24 | fallback() external {
25 | uint256 anUintToFillSpace;
26 | }
27 |
28 | fallback() external onlyOwner {
29 | uint256 anUintToFillSpace;
30 | }
31 |
32 | fallback() external virtual {}
33 |
34 | fallback() external payable {}
35 | function() external payable {}
36 | }
37 |
38 | contract FallbackWithReceive {
39 | constructor() {}
40 |
41 | function() {
42 | uint256 anUintToFillSpace;
43 | }
44 |
45 | function() external onlyOwner {}
46 |
47 | fallback() external {
48 | uint256 anUintToFillSpace;
49 | }
50 |
51 | receive() external payable onlyOwner {}
52 | }
53 |
54 | contract FallbackNoReceive2 {
55 | constructor() {}
56 |
57 | function() {
58 | uint256 anUintToFillSpace;
59 | }
60 |
61 | function() external onlyOwner {}
62 |
63 | fallback() external {
64 | uint256 anUintToFillSpace;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/e2e/08-autofix/payable-fallback/Foo1AfterFix.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | pragma solidity ^0.8.0;
3 |
4 | contract FallbackNoReceive1 {
5 | constructor() {}
6 |
7 | function anyFunction() {}
8 |
9 | function() payable public {}
10 |
11 | function() payable {
12 | uint256 anUintToFillSpace;
13 | }
14 |
15 | function() payable external onlyOwner {}
16 |
17 | function() payable virtual {
18 | uint256 anUintToFillSpace;
19 | }
20 |
21 | //// fallback explicit
22 | fallback() payable external {}
23 |
24 | fallback() payable external {
25 | uint256 anUintToFillSpace;
26 | }
27 |
28 | fallback() payable external onlyOwner {
29 | uint256 anUintToFillSpace;
30 | }
31 |
32 | fallback() payable external virtual {}
33 |
34 | fallback() external payable {}
35 | function() external payable {}
36 | }
37 |
38 | contract FallbackWithReceive {
39 | constructor() {}
40 |
41 | function() {
42 | uint256 anUintToFillSpace;
43 | }
44 |
45 | function() external onlyOwner {}
46 |
47 | fallback() external {
48 | uint256 anUintToFillSpace;
49 | }
50 |
51 | receive() external payable onlyOwner {}
52 | }
53 |
54 | contract FallbackNoReceive2 {
55 | constructor() {}
56 |
57 | function() payable {
58 | uint256 anUintToFillSpace;
59 | }
60 |
61 | function() payable external onlyOwner {}
62 |
63 | fallback() payable external {
64 | uint256 anUintToFillSpace;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/e2e/08-autofix/payable-fallback/Foo1BeforeFix.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | pragma solidity ^0.8.0;
3 |
4 | contract FallbackNoReceive1 {
5 | constructor() {}
6 |
7 | function anyFunction() {}
8 |
9 | function() public {}
10 |
11 | function() {
12 | uint256 anUintToFillSpace;
13 | }
14 |
15 | function() external onlyOwner {}
16 |
17 | function() virtual {
18 | uint256 anUintToFillSpace;
19 | }
20 |
21 | //// fallback explicit
22 | fallback() external {}
23 |
24 | fallback() external {
25 | uint256 anUintToFillSpace;
26 | }
27 |
28 | fallback() external onlyOwner {
29 | uint256 anUintToFillSpace;
30 | }
31 |
32 | fallback() external virtual {}
33 |
34 | fallback() external payable {}
35 | function() external payable {}
36 | }
37 |
38 | contract FallbackWithReceive {
39 | constructor() {}
40 |
41 | function() {
42 | uint256 anUintToFillSpace;
43 | }
44 |
45 | function() external onlyOwner {}
46 |
47 | fallback() external {
48 | uint256 anUintToFillSpace;
49 | }
50 |
51 | receive() external payable onlyOwner {}
52 | }
53 |
54 | contract FallbackNoReceive2 {
55 | constructor() {}
56 |
57 | function() {
58 | uint256 anUintToFillSpace;
59 | }
60 |
61 | function() external onlyOwner {}
62 |
63 | fallback() external {
64 | uint256 anUintToFillSpace;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/e2e/08-autofix/private-vars-underscore/.solhint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "private-vars-leading-underscore": ["error",{"strict":false}],
4 | "compiler-version": "off"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/e2e/08-autofix/quotes/.doubleQuotes.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "quotes": ["error", "double"],
4 | "compiler-version": "off"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/e2e/08-autofix/quotes/.singleQuotes.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "quotes": ["error", "single"],
4 | "compiler-version": "off"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/e2e/08-autofix/quotes/Foo1.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | pragma solidity ^0.8.0;
3 |
4 | import "lib1.sol";
5 | import 'lib2.sol';
6 | import { something1 } from "lib3.sol";
7 | import { something2 } from 'lib4.sol';
8 | import { something1 as smg1 } from "lib3.sol";
9 | import { something2 as smg2 } from 'lib4.sol';
10 |
11 | contract Generic {
12 |
13 | string private constant STR1 = "You shall not 'pass' !";
14 | string private constant STR2 = 'You shall not "pass" !';
15 |
16 | function asmSingle() external view {
17 | assembly { 'abc' }
18 | assembly { dataSize('uint') }
19 | assembly { linkerSymbol('uint') }
20 | assembly { let hexString := '48656c6c6f2c2027576f726c64212722' }
21 | }
22 |
23 | function asmDouble() external view {
24 | assembly { "abc" }
25 | assembly { dataSize("uint") }
26 | assembly { linkerSymbol("uint") }
27 | assembly { let hexString := "48656c6c6f2c2027576f726c64212722" }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/e2e/08-autofix/quotes/Foo1AfterFixDouble.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | pragma solidity ^0.8.0;
3 |
4 | import "lib1.sol";
5 | import "lib2.sol";
6 | import { something1 } from "lib3.sol";
7 | import { something2 } from "lib4.sol";
8 | import { something1 as smg1 } from "lib3.sol";
9 | import { something2 as smg2 } from "lib4.sol";
10 |
11 | contract Generic {
12 |
13 | string private constant STR1 = "You shall not 'pass' !";
14 | string private constant STR2 = "You shall not 'pass' !";
15 |
16 | function asmSingle() external view {
17 | assembly { "abc" }
18 | assembly { dataSize("uint") }
19 | assembly { linkerSymbol("uint") }
20 | assembly { let hexString := "48656c6c6f2c2027576f726c64212722" }
21 | }
22 |
23 | function asmDouble() external view {
24 | assembly { "abc" }
25 | assembly { dataSize("uint") }
26 | assembly { linkerSymbol("uint") }
27 | assembly { let hexString := "48656c6c6f2c2027576f726c64212722" }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/e2e/08-autofix/quotes/Foo1AfterFixSingle.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | pragma solidity ^0.8.0;
3 |
4 | import 'lib1.sol';
5 | import 'lib2.sol';
6 | import { something1 } from 'lib3.sol';
7 | import { something2 } from 'lib4.sol';
8 | import { something1 as smg1 } from 'lib3.sol';
9 | import { something2 as smg2 } from 'lib4.sol';
10 |
11 | contract Generic {
12 |
13 | string private constant STR1 = 'You shall not "pass" !';
14 | string private constant STR2 = 'You shall not "pass" !';
15 |
16 | function asmSingle() external view {
17 | assembly { 'abc' }
18 | assembly { dataSize('uint') }
19 | assembly { linkerSymbol('uint') }
20 | assembly { let hexString := '48656c6c6f2c2027576f726c64212722' }
21 | }
22 |
23 | function asmDouble() external view {
24 | assembly { 'abc' }
25 | assembly { dataSize('uint') }
26 | assembly { linkerSymbol('uint') }
27 | assembly { let hexString := '48656c6c6f2c2027576f726c64212722' }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/e2e/08-autofix/quotes/Foo1BeforeFix.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | pragma solidity ^0.8.0;
3 |
4 | import "lib1.sol";
5 | import 'lib2.sol';
6 | import { something1 } from "lib3.sol";
7 | import { something2 } from 'lib4.sol';
8 | import { something1 as smg1 } from "lib3.sol";
9 | import { something2 as smg2 } from 'lib4.sol';
10 |
11 | contract Generic {
12 |
13 | string private constant STR1 = "You shall not 'pass' !";
14 | string private constant STR2 = 'You shall not "pass" !';
15 |
16 | function asmSingle() external view {
17 | assembly { 'abc' }
18 | assembly { dataSize('uint') }
19 | assembly { linkerSymbol('uint') }
20 | assembly { let hexString := '48656c6c6f2c2027576f726c64212722' }
21 | }
22 |
23 | function asmDouble() external view {
24 | assembly { "abc" }
25 | assembly { dataSize("uint") }
26 | assembly { linkerSymbol("uint") }
27 | assembly { let hexString := "48656c6c6f2c2027576f726c64212722" }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/e2e/10-import-path-check/filesystem01/project/.solhintS01.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": { "import-path-check": [ "error", [] ] }
3 | }
4 |
--------------------------------------------------------------------------------
/e2e/10-import-path-check/filesystem01/project/contracts/Lib.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.6.0;
3 |
4 | contract Foo {
5 | uint256 public constant test1 = 1;
6 | uint256 TEST2;
7 |
8 | constructor() {}
9 |
10 | function TEST() {}
11 |
12 | modifier ZAR_tok() {}
13 |
14 | uint256 SOSO;
15 | }
16 |
--------------------------------------------------------------------------------
/e2e/10-import-path-check/filesystem01/project/contracts/Test.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity ^0.8.0;
3 |
4 | import "./Lib.sol";
5 |
6 | contract Test {}
7 |
--------------------------------------------------------------------------------
/e2e/10-import-path-check/filesystem02/project/.solhintS02.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": { "import-path-check": [ "error", ["/blockchain"] ] }
3 | }
4 |
--------------------------------------------------------------------------------
/e2e/10-import-path-check/filesystem02/project/contracts/Test.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity ^0.8.0;
3 |
4 | import {Helper} from "../shared/Helper.sol";
5 |
6 | contract Test {}
7 |
--------------------------------------------------------------------------------
/e2e/10-import-path-check/filesystem02/project/shared/Helper.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity ^0.8.0;
3 |
4 | import "./Lib.sol";
5 |
6 | contract Test {}
7 |
--------------------------------------------------------------------------------
/e2e/10-import-path-check/filesystem03/project/.solhintS03.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": { "import-path-check": [ "error", [] ] }
3 | }
4 |
--------------------------------------------------------------------------------
/e2e/10-import-path-check/filesystem03/project/contracts/Test.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity ^0.8.0;
3 |
4 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
5 |
6 | contract Test {}
7 |
--------------------------------------------------------------------------------
/e2e/10-import-path-check/filesystem04/project/.solhintF04.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": { "import-path-check": [ "error", [] ] }
3 | }
4 |
--------------------------------------------------------------------------------
/e2e/10-import-path-check/filesystem04/project/contracts/Test.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity ^0.8.0;
3 |
4 | import "./Missing.sol";
5 |
6 | contract Test {}
7 |
--------------------------------------------------------------------------------
/e2e/pre-commit-hook/.solhint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "solhint:recommended"
3 | }
4 |
--------------------------------------------------------------------------------
/e2e/pre-commit-hook/Counter.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | pragma solidity ^0.8.26;
3 |
4 | contract Counter {
5 | uint256 public number;
6 |
7 | function setNumber(uint256 newNumber) public {
8 | number = newNumber;
9 | }
10 |
11 | function increment() public {
12 | number++;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/e2e/pre-commit-hook/test.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -o errtrace -o nounset -o pipefail -o errexit
4 |
5 | SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
6 |
7 | # Create temp working directory for mock repo
8 | MOCK_REPO=$(mktemp -d)
9 | if [[ ! "$MOCK_REPO" || ! -d "$MOCK_REPO" ]]; then
10 | echo "Could not create temp dir"
11 | exit 1
12 | fi
13 | function cleanup {
14 | echo "Deleting temp working directory $MOCK_REPO"
15 | rm -rf "$MOCK_REPO"
16 | }
17 |
18 | trap cleanup EXIT
19 |
20 | # Filling the mock repo
21 | pushd "$MOCK_REPO" >/dev/null || exit 1
22 | git init --initial-branch=master
23 | git config user.email "test@example.com"
24 | git config user.name "pre-commit test"
25 | cp "$SCRIPT_DIR/.solhint.json" "$SCRIPT_DIR/Counter.sol" .
26 | git add .
27 | git commit -m "Initial commit"
28 |
29 | # Run pre-commit inside the mock repo while referencing the solhint directory,
30 | # where the .pre-commit-hooks.yaml is located.
31 | pre-commit try-repo "$SCRIPT_DIR/../.." solhint --verbose --color=always --all-files
32 |
--------------------------------------------------------------------------------
/funding.json:
--------------------------------------------------------------------------------
1 | {
2 | "opRetro": {
3 | "projectId": "0xfa7d950cfda2c634b052b6c07e75daaa95dd22ac1f220b6862cfd24221d4cabc"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/lib/apply-fixes.js:
--------------------------------------------------------------------------------
1 | function applyFixes(fixes, inputSrc) {
2 | if (fixes.length === 0) {
3 | return {
4 | fixed: false,
5 | }
6 | }
7 |
8 | let output = ''
9 |
10 | let i = 0
11 | let fixIndex = 0
12 |
13 | while (i < inputSrc.length) {
14 | if (fixIndex < fixes.length) {
15 | // Skip fixes from the past
16 | if (i > fixes[fixIndex].range[1]) {
17 | fixIndex += 1
18 | continue
19 | }
20 |
21 | output += inputSrc.slice(i, fixes[fixIndex].range[0])
22 | output += fixes[fixIndex].text
23 | i = fixes[fixIndex].range[1] + 1
24 | fixIndex += 1
25 | } else {
26 | output += inputSrc.slice(i)
27 | break
28 | }
29 | }
30 |
31 | return {
32 | fixed: true,
33 | output,
34 | }
35 | }
36 |
37 | module.exports = applyFixes
38 |
--------------------------------------------------------------------------------
/lib/common/ajv.js:
--------------------------------------------------------------------------------
1 | const Ajv = require('ajv')
2 | const metaSchema = require('ajv/lib/refs/json-schema-draft-04.json')
3 |
4 | const ajv = new Ajv({
5 | meta: false,
6 | validateSchema: false,
7 | missingRefs: 'ignore',
8 | verbose: true,
9 | schemaId: 'auto',
10 | })
11 |
12 | ajv.addMetaSchema(metaSchema)
13 | ajv._opts.defaultMeta = metaSchema.id
14 |
15 | module.exports = ajv
16 |
--------------------------------------------------------------------------------
/lib/common/ast-printer.js:
--------------------------------------------------------------------------------
1 | const antlr4 = require('antlr4')
2 |
3 | class AstPrinter {
4 | constructor(tokenStream) {
5 | this.tokenStream = tokenStream
6 | }
7 |
8 | print(ctx) {
9 | this.explore(ctx, 0)
10 | }
11 |
12 | explore(ctx, indentation) {
13 | const ruleName = ctx.parser.ruleNames[ctx.ruleIndex]
14 |
15 | console.log(' '.repeat(indentation + 1) + ruleName + ' ' + ctx.getText())
16 |
17 | for (let i = 0; i < ctx.getChildCount(); i++) {
18 | const element = ctx.getChild(i)
19 |
20 | if (element instanceof antlr4.ParserRuleContext) {
21 | this.explore(element, indentation + 1)
22 | } else {
23 | console.log(
24 | ' '.repeat(indentation + 2) + element.constructor.name + ' ' + element.getText()
25 | )
26 | }
27 | }
28 | }
29 | }
30 |
31 | module.exports = AstPrinter
32 |
--------------------------------------------------------------------------------
/lib/common/ast-types.js:
--------------------------------------------------------------------------------
1 | function isFallbackFunction(node) {
2 | return isFunctionDefinition(node) && (node.isFallback || node.isReceiveEther)
3 | }
4 |
5 | function isReceiveFunction(node) {
6 | return isFunctionDefinition(node) && node.isReceiveEther
7 | }
8 |
9 | function isFunctionDefinition(node) {
10 | return node.type === 'FunctionDefinition'
11 | }
12 |
13 | function isStructDefinition(node) {
14 | return node.type === 'StructDefinition'
15 | }
16 |
17 | function isEnumDefinition(node) {
18 | return node.type === 'EnumDefinition'
19 | }
20 |
21 | module.exports = {
22 | isFallbackFunction,
23 | isReceiveFunction,
24 | isFunctionDefinition,
25 | isStructDefinition,
26 | isEnumDefinition,
27 | }
28 |
--------------------------------------------------------------------------------
/lib/common/blank-line-counter.js:
--------------------------------------------------------------------------------
1 | const { stopLine, lineOf } = require('./tokens')
2 |
3 | class BlankLineCounter {
4 | constructor() {
5 | this.tokenLines = new Set()
6 | }
7 |
8 | countOfEmptyLinesBetween(start, end) {
9 | return this.countOfEmptyLinesBetweenTokens(stopLine(start), lineOf(end))
10 | }
11 |
12 | countOfEmptyLinesBetweenTokens(start, end) {
13 | let count = 0
14 |
15 | for (let i = start + 1; i < end; i += 1) {
16 | if (!this.tokenLines.has(i)) {
17 | count++
18 | }
19 | }
20 |
21 | return count
22 | }
23 |
24 | calcTokenLines(ctx) {
25 | if (this.tokenLines.size === 0) {
26 | ctx.parser._input.tokens.forEach((i) => this.addTokenLinesToMap(i))
27 | }
28 | }
29 |
30 | addTokenLinesToMap(token) {
31 | const HIDDEN = 1
32 | if (token.channel === HIDDEN) {
33 | const linesCount = token.text.split('\n').length
34 | for (let curLine = token.line; curLine < token.line + linesCount; curLine += 1) {
35 | this.tokenLines.add(curLine)
36 | }
37 | } else {
38 | this.tokenLines.add(token.line)
39 | }
40 | }
41 | }
42 |
43 | module.exports = BlankLineCounter
44 |
--------------------------------------------------------------------------------
/lib/common/errors.js:
--------------------------------------------------------------------------------
1 | class ConfigMissingError extends Error {
2 | constructor(configName) {
3 | let message = `Failed to load a solhint's config file.`
4 | if (configName) message = `Failed to load config "${configName}" to extend from.`
5 | super(message)
6 | }
7 | }
8 |
9 | module.exports = {
10 | ConfigMissingError,
11 | }
12 |
--------------------------------------------------------------------------------
/lib/common/identifier-naming.js:
--------------------------------------------------------------------------------
1 | function match(text, regex) {
2 | return text.replace(regex, '').length === 0
3 | }
4 |
5 | module.exports = {
6 | isMixedCase(text) {
7 | return match(text, /[_]*[a-z$]+[a-zA-Z0-9$]*[_]?/)
8 | },
9 |
10 | isNotMixedCase(text) {
11 | return !this.isMixedCase(text)
12 | },
13 |
14 | isCapWords(text) {
15 | return match(text, /[A-Z$]+[a-zA-Z0-9$]*/)
16 | },
17 |
18 | isNotCapWords(text) {
19 | return !this.isCapWords(text)
20 | },
21 |
22 | isUpperSnakeCase(text) {
23 | return match(text, /_{0,2}[A-Z0-9$]+[_A-Z0-9$]*/)
24 | },
25 |
26 | isNotUpperSnakeCase(text) {
27 | return !this.isUpperSnakeCase(text)
28 | },
29 |
30 | hasLeadingUnderscore(text) {
31 | return text && text[0] === '_'
32 | },
33 |
34 | isFoundryTestCase(text) {
35 | // this one checks CamelCase after test keyword
36 | // const regexTest = /^test(Fork)?(Fuzz)?(Fail)?(_)?[A-Z](Revert(If_|When_){1})?\w{1,}$/
37 |
38 | const regexTest = /^test(Fork)?(Fuzz)?(Fail)?(_)?(Revert(If_|When_){1})?\w{1,}$/
39 | const matchRegexTest = match(text, regexTest)
40 |
41 | // this one checks CamelCase after test keyword
42 | // const regexInvariant = /^(invariant|statefulFuzz)(_)?[A-Z]\w{1,}$/
43 | const regexInvariant = /^(invariant|statefulFuzz)(_)?\w{1,}$/
44 | const matchRegexInvariant = match(text, regexInvariant)
45 |
46 | return matchRegexTest || matchRegexInvariant
47 | },
48 | }
49 |
--------------------------------------------------------------------------------
/lib/common/utils.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs')
2 | const path = require('path')
3 |
4 | const getLocFromIndex = (text, index) => {
5 | let line = 1
6 | let column = 0
7 | let i = 0
8 | while (i < index) {
9 | if (text[i] === '\n') {
10 | line++
11 | column = 0
12 | } else {
13 | column++
14 | }
15 | i++
16 | }
17 |
18 | return { line, column }
19 | }
20 |
21 | const walkSync = (dir, filelist = []) => {
22 | fs.readdirSync(dir).forEach((file) => {
23 | filelist = fs.statSync(path.join(dir, file)).isDirectory()
24 | ? walkSync(path.join(dir, file), filelist)
25 | : filelist.concat(path.join(dir, file))
26 | })
27 | return filelist
28 | }
29 |
30 | module.exports = {
31 | getLocFromIndex,
32 | walkSync,
33 | }
34 |
--------------------------------------------------------------------------------
/lib/config/config-schema.js:
--------------------------------------------------------------------------------
1 | const baseConfigProperties = {
2 | rules: { type: 'object' },
3 | excludedFiles: { type: 'array' },
4 | extends: { anyOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }] },
5 | globals: { type: 'object' },
6 | env: { type: 'object' },
7 | parserOptions: { type: 'object' },
8 | plugins: { type: 'array' },
9 | }
10 |
11 | const configSchema = {
12 | type: 'object',
13 | properties: baseConfigProperties,
14 | additionalProperties: false,
15 | }
16 |
17 | module.exports = configSchema
18 |
--------------------------------------------------------------------------------
/lib/doc/utils.js:
--------------------------------------------------------------------------------
1 | const { validSeverityMap, invalidSeverityMap } = require('../config/config-validator')
2 |
3 | const formatEnum = (options) => options.map((op) => JSON.stringify(op)).join(', ')
4 | const ruleSeverityEnum = formatEnum([...validSeverityMap, ...invalidSeverityMap])
5 |
6 | module.exports = {
7 | ruleSeverityEnum,
8 | severityDescription: `Rule severity. Must be one of ${ruleSeverityEnum}.`,
9 | formatEnum,
10 | }
11 |
--------------------------------------------------------------------------------
/lib/formatters/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright OpenJS Foundation and other contributors,
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/lib/formatters/README.md:
--------------------------------------------------------------------------------
1 | # Eslint formatters
2 |
3 | files in this directory are pulled from eslint repository:
4 |
5 | - table.js: eslint - Gajus Kuizinas
6 | - unix.js: eslint - oshi-shinobu
7 | - tap.js: eslint - Jonathan Kingston
8 | - stylish.js: eslint - Sindre Sorhus
9 | - json.js: eslint - Artur Lukianov
10 | - compact.js: eslint - Nicholas C. Zakas
11 | - sarif.js: [@microsoft/eslint-formatter-sarif](https://www.npmjs.com/package/@microsoft/eslint-formatter-sarif)
12 |
--------------------------------------------------------------------------------
/lib/rules/best-practices/index.js:
--------------------------------------------------------------------------------
1 | const CodeComplexityChecker = require('./code-complexity')
2 | const FunctionMaxLinesChecker = require('./function-max-lines')
3 | const MaxLineLengthChecker = require('./max-line-length')
4 | const MaxStatesCountChecker = require('./max-states-count')
5 | const NoEmptyBlocksChecker = require('./no-empty-blocks')
6 | const NoUnusedVarsChecker = require('./no-unused-vars')
7 | const PayableFallbackChecker = require('./payable-fallback')
8 | const ReasonStringChecker = require('./reason-string')
9 | const NoConsoleLogChecker = require('./no-console')
10 | const NoGlobalImportsChecker = require('./no-global-import')
11 | const NoUnusedImportsChecker = require('./no-unused-import')
12 | const ExplicitTypesChecker = require('./explicit-types')
13 | const OneContractPerFileChecker = require('./one-contract-per-file')
14 | const InterfaceStartsWithIChecker = require('./interface-starts-with-i')
15 |
16 | module.exports = function checkers(reporter, config, inputSrc, tokens) {
17 | return [
18 | new CodeComplexityChecker(reporter, config),
19 | new FunctionMaxLinesChecker(reporter, config),
20 | new MaxLineLengthChecker(reporter, config, inputSrc),
21 | new MaxStatesCountChecker(reporter, config),
22 | new NoEmptyBlocksChecker(reporter),
23 | new NoUnusedVarsChecker(reporter),
24 | new PayableFallbackChecker(reporter),
25 | new ReasonStringChecker(reporter, config),
26 | new NoConsoleLogChecker(reporter),
27 | new NoGlobalImportsChecker(reporter),
28 | new NoUnusedImportsChecker(reporter, tokens),
29 | new ExplicitTypesChecker(reporter, config),
30 | new OneContractPerFileChecker(reporter),
31 | new InterfaceStartsWithIChecker(reporter),
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/lib/rules/best-practices/interface-starts-with-i.js:
--------------------------------------------------------------------------------
1 | const BaseChecker = require('../base-checker')
2 |
3 | const ruleId = 'interface-starts-with-i'
4 | const meta = {
5 | type: 'naming',
6 | docs: {
7 | description: 'Solidity Interfaces names should start with an `I`',
8 | category: 'Style Guide Rules',
9 | examples: {
10 | good: [
11 | {
12 | description: 'Interface name starts with I',
13 | code: `interface IFoo { function foo () external; }`,
14 | },
15 | ],
16 | bad: [
17 | {
18 | description: `Interface name doesn't start with I`,
19 | code: `interface Foo { function foo () external; }`,
20 | },
21 | ],
22 | },
23 | },
24 |
25 | recommended: false,
26 | defaultSetup: 'warn',
27 | schema: [],
28 | }
29 |
30 | class InterfaceStartsWithIChecker extends BaseChecker {
31 | constructor(reporter) {
32 | super(reporter, ruleId, meta)
33 | }
34 |
35 | ContractDefinition(node) {
36 | if (node.kind !== 'interface') return
37 | const interfaceName = node.name
38 |
39 | if (!interfaceName.startsWith('I')) {
40 | this.error(node, `Interface name '${interfaceName}' must start with "I"`)
41 | }
42 | }
43 | }
44 |
45 | module.exports = InterfaceStartsWithIChecker
46 |
--------------------------------------------------------------------------------
/lib/rules/best-practices/no-global-import.js:
--------------------------------------------------------------------------------
1 | const BaseChecker = require('../base-checker')
2 |
3 | const ruleId = 'no-global-import'
4 | const meta = {
5 | type: 'best-practices',
6 |
7 | docs: {
8 | description: 'Import statement includes an entire file instead of selected symbols.',
9 | category: 'Best Practices Rules',
10 | examples: {
11 | bad: [
12 | { description: 'import all members from a file', code: 'import * from "foo.sol"' },
13 | { description: 'import an entire file', code: 'import "foo.sol"' },
14 | ],
15 | good: [
16 | { description: 'import names explicitly', code: 'import {A} from "./A.sol"' },
17 | { description: 'import entire file into a name', code: 'import "./A.sol" as A' },
18 | { description: 'import entire file into a name', code: 'import * as A from "./A.sol"' },
19 | ],
20 | },
21 | },
22 |
23 | recommended: true,
24 | defaultSetup: 'warn',
25 |
26 | schema: null,
27 | }
28 |
29 | class NoGlobalImportsChecker extends BaseChecker {
30 | constructor(reporter) {
31 | super(reporter, ruleId, meta)
32 | }
33 |
34 | ImportDirective(node) {
35 | if (!(node.symbolAliases || node.unitAlias)) {
36 | this.error(
37 | node,
38 | `global import of path ${node.path} is not allowed. Specify names to import individually or bind all exports of the module into a name (import "path" as Name)`
39 | )
40 | }
41 | }
42 | }
43 |
44 | module.exports = NoGlobalImportsChecker
45 |
--------------------------------------------------------------------------------
/lib/rules/best-practices/one-contract-per-file.js:
--------------------------------------------------------------------------------
1 | const BaseChecker = require('../base-checker')
2 | const { severityDescription } = require('../../doc/utils')
3 |
4 | const DEFAULT_SEVERITY = 'warn'
5 |
6 | const ruleId = 'one-contract-per-file'
7 | const meta = {
8 | type: 'best-practices',
9 |
10 | docs: {
11 | description:
12 | 'Enforces the use of ONE Contract per file see [here](https://docs.soliditylang.org/en/v0.8.21/style-guide.html#contract-and-library-names)',
13 | category: 'Best Practices Rules',
14 | options: [
15 | {
16 | description: severityDescription,
17 | default: DEFAULT_SEVERITY,
18 | },
19 | ],
20 | },
21 |
22 | recommended: true,
23 | defaultSetup: DEFAULT_SEVERITY,
24 |
25 | schema: null,
26 | }
27 |
28 | class OneContractPerFileChecker extends BaseChecker {
29 | constructor(reporter) {
30 | super(reporter, ruleId, meta)
31 | }
32 |
33 | SourceUnit(node) {
34 | const contractDefinitionCount = node.children.reduce((count, child) => {
35 | if (child.type === 'ContractDefinition' && child.kind !== 'interface') {
36 | return count + 1
37 | }
38 | return count
39 | }, 0)
40 |
41 | if (contractDefinitionCount > 1) {
42 | this.error(
43 | node,
44 | `Found more than One contract per file. ${contractDefinitionCount} contracts found!`
45 | )
46 | }
47 | }
48 | }
49 |
50 | module.exports = OneContractPerFileChecker
51 |
--------------------------------------------------------------------------------
/lib/rules/deprecations/base-deprecation.js:
--------------------------------------------------------------------------------
1 | const BaseChecker = require('../base-checker')
2 |
3 | class BaseDeprecation extends BaseChecker {
4 | constructor(reporter, ruleId, meta) {
5 | super(reporter, ruleId, meta)
6 | this.active = false
7 | this.deprecationVersion() // to ensure we have one.
8 | }
9 |
10 | PragmaDirective(node) {
11 | const pragma = node.name
12 | const value = node.value
13 | if (pragma === 'solidity') {
14 | const contextVersion = value.replace(/[^0-9.]/g, '').split('.')
15 | const deprecationAt = this.deprecationVersion().split('.')
16 | this.active =
17 | contextVersion[0] > deprecationAt[0] ||
18 | contextVersion[1] > deprecationAt[1] ||
19 | contextVersion[2] >= deprecationAt[2]
20 | this.version = value
21 | }
22 | }
23 |
24 | deprecationVersion() {
25 | throw new Error('Implementations must supply a deprecation version!')
26 | }
27 | }
28 |
29 | module.exports = BaseDeprecation
30 |
--------------------------------------------------------------------------------
/lib/rules/deprecations/constructor-syntax.js:
--------------------------------------------------------------------------------
1 | const BaseDeprecation = require('./base-deprecation')
2 |
3 | const ruleId = 'constructor-syntax'
4 | const meta = {
5 | type: 'best-practices',
6 |
7 | docs: {
8 | description: 'Constructors should use the new constructor keyword.',
9 | category: 'Best Practices Rules',
10 | },
11 |
12 | recommended: false,
13 | defaultSetup: 'warn',
14 |
15 | schema: null,
16 | }
17 |
18 | class ConstructorSyntax extends BaseDeprecation {
19 | constructor(reporter) {
20 | super(reporter, ruleId, meta)
21 | }
22 |
23 | deprecationVersion() {
24 | return '0.4.22'
25 | }
26 |
27 | PragmaDirective(node) {
28 | super.PragmaDirective(node)
29 | }
30 |
31 | FunctionDefinition(node) {
32 | if (node.isConstructor) {
33 | if (node.name === null) {
34 | if (!this.active) {
35 | const message = 'Constructor keyword not available before 0.4.22 (' + this.version + ')'
36 | this.error(node, message)
37 | }
38 | } else if (this.active) {
39 | this.warn(node, 'Constructors should use the new constructor keyword.')
40 | }
41 | }
42 | }
43 | }
44 |
45 | module.exports = ConstructorSyntax
46 |
--------------------------------------------------------------------------------
/lib/rules/deprecations/index.js:
--------------------------------------------------------------------------------
1 | const ConstructorSyntax = require('./constructor-syntax')
2 |
3 | module.exports = (reporter) => [new ConstructorSyntax(reporter)]
4 |
--------------------------------------------------------------------------------
/lib/rules/gas-consumption/gas-multitoken1155.js:
--------------------------------------------------------------------------------
1 | const BaseChecker = require('../base-checker')
2 |
3 | const ruleId = 'gas-multitoken1155'
4 | const meta = {
5 | type: 'gas-consumption',
6 |
7 | docs: {
8 | description: 'ERC1155 is a cheaper non-fungible token than ERC721',
9 | category: 'Gas Consumption Rules',
10 | notes: [
11 | {
12 | note: '[source](https://www.rareskills.io/post/gas-optimization?postId=c9db474a-ff97-4fa3-a51d-fe13ccb8fe3b#viewer-8v8t9) of the rule initiative',
13 | },
14 | ],
15 | },
16 |
17 | recommended: false,
18 | defaultSetup: 'warn',
19 |
20 | schema: null,
21 | }
22 |
23 | class GasMultitoken1155 extends BaseChecker {
24 | constructor(reporter) {
25 | super(reporter, ruleId, meta)
26 | }
27 |
28 | hasERC721String(path) {
29 | // Convert both the input string and the substring to lowercase for case-insensitive comparison
30 | const lowercaseInput = path.toLowerCase()
31 | const lowercaseSubstring = 'erc721'
32 |
33 | // Check if the lowercase input string contains the lowercase substring
34 | return lowercaseInput.includes(lowercaseSubstring)
35 | }
36 |
37 | ImportDirective(node) {
38 | if (this.hasERC721String(node.path)) {
39 | this.error(node, 'GC: ERC721 import found - Use of ERC1155 recommended')
40 | }
41 | }
42 | }
43 |
44 | module.exports = GasMultitoken1155
45 |
--------------------------------------------------------------------------------
/lib/rules/gas-consumption/gas-named-return-values.js:
--------------------------------------------------------------------------------
1 | const BaseChecker = require('../base-checker')
2 | const { severityDescription } = require('../../doc/utils')
3 |
4 | const DEFAULT_SEVERITY = 'warn'
5 |
6 | const ruleId = 'gas-named-return-values'
7 | const meta = {
8 | type: 'gas-consumption',
9 |
10 | docs: {
11 | description: `Enforce the return values of a function to be named`,
12 | category: 'Gas Consumption Rules',
13 | options: [
14 | {
15 | description: severityDescription,
16 | default: DEFAULT_SEVERITY,
17 | },
18 | ],
19 | examples: {
20 | good: [
21 | {
22 | description: 'Function definition with named return values',
23 | code: 'function checkBalance(address wallet) external view returns(uint256 retBalance) {}',
24 | },
25 | ],
26 | bad: [
27 | {
28 | description: 'Function definition with UNNAMED return values',
29 | code: 'function checkBalance(address wallet) external view returns(uint256) {}',
30 | },
31 | ],
32 | },
33 | },
34 |
35 | recommended: false,
36 | defaultSetup: DEFAULT_SEVERITY,
37 |
38 | schema: null,
39 | }
40 |
41 | class GasNamedReturnValuesChecker extends BaseChecker {
42 | constructor(reporter) {
43 | super(reporter, ruleId, meta)
44 | }
45 |
46 | FunctionDefinition(node) {
47 | if (node.returnParameters) {
48 | let index = 0
49 | for (const returnValue of node.returnParameters) {
50 | if (!returnValue.name) {
51 | this.error(node, `GC: Named return value is missing - Index ${index}`)
52 | }
53 | index++
54 | }
55 | }
56 | }
57 | }
58 |
59 | module.exports = GasNamedReturnValuesChecker
60 |
--------------------------------------------------------------------------------
/lib/rules/gas-consumption/gas-strict-inequalities.js:
--------------------------------------------------------------------------------
1 | const BaseChecker = require('../base-checker')
2 |
3 | const ruleId = 'gas-strict-inequalities'
4 | const meta = {
5 | type: 'gas-consumption',
6 |
7 | docs: {
8 | description: 'Suggest Strict Inequalities over non Strict ones',
9 | category: 'Gas Consumption Rules',
10 | notes: [
11 | {
12 | note: 'Strict inequality does not always saves gas. It is dependent on the context of the surrounding opcodes',
13 | },
14 | {
15 | note: '[source 1](https://coinsbench.com/comprehensive-guide-tips-and-tricks-for-gas-optimization-in-solidity-5380db734404) of the rule initiative (see Less/Greater Than vs Less/Greater Than or Equal To)',
16 | },
17 | {
18 | note: '[source 2](https://www.rareskills.io/post/gas-optimization?postId=c9db474a-ff97-4fa3-a51d-fe13ccb8fe3b#viewer-7b77t) of the rule initiative',
19 | },
20 | ],
21 | },
22 |
23 | recommended: false,
24 | defaultSetup: 'warn',
25 |
26 | schema: null,
27 | }
28 |
29 | class GasStrictInequalities extends BaseChecker {
30 | constructor(reporter) {
31 | super(reporter, ruleId, meta)
32 | }
33 |
34 | BinaryOperation(node) {
35 | if (node.operator === '>=' || node.operator === '<=') {
36 | this.reportError(node)
37 | }
38 | }
39 |
40 | reportError(node) {
41 | this.error(node, `GC: Non strict inequality found. Try converting to a strict one`)
42 | }
43 | }
44 |
45 | module.exports = GasStrictInequalities
46 |
--------------------------------------------------------------------------------
/lib/rules/gas-consumption/index.js:
--------------------------------------------------------------------------------
1 | const GasMultitoken1155 = require('./gas-multitoken1155')
2 | const GasSmallStrings = require('./gas-small-strings')
3 | const GasIndexedEvents = require('./gas-indexed-events')
4 | const GasCalldataParameters = require('./gas-calldata-parameters')
5 | const GasIncrementByOne = require('./gas-increment-by-one')
6 | const GasStructPacking = require('./gas-struct-packing')
7 | const GasLengthInLoops = require('./gas-length-in-loops')
8 | const GasStrictInequalities = require('./gas-strict-inequalities')
9 | const GasNamedReturnValuesChecker = require('./gas-named-return-values')
10 | const GasCustomErrorsChecker = require('./gas-custom-errors')
11 |
12 | module.exports = function checkers(reporter, config) {
13 | return [
14 | new GasMultitoken1155(reporter, config),
15 | new GasSmallStrings(reporter, config),
16 | new GasIndexedEvents(reporter, config),
17 | new GasCalldataParameters(reporter, config),
18 | new GasIncrementByOne(reporter, config),
19 | new GasStructPacking(reporter, config),
20 | new GasLengthInLoops(reporter, config),
21 | new GasStrictInequalities(reporter, config),
22 | new GasNamedReturnValuesChecker(reporter),
23 | new GasCustomErrorsChecker(reporter),
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/lib/rules/miscellaneous/index.js:
--------------------------------------------------------------------------------
1 | const QuotesChecker = require('./quotes')
2 | const ComprehensiveInterfaceChecker = require('./comprehensive-interface')
3 | const DuplicatedImportsChecker = require('./duplicated-imports')
4 | const ImportPathChecker = require('./import-path-check')
5 |
6 | module.exports = function checkers(reporter, config, tokens, fileName) {
7 | return [
8 | new QuotesChecker(reporter, config, tokens),
9 | new ComprehensiveInterfaceChecker(reporter, config, tokens),
10 | new DuplicatedImportsChecker(reporter),
11 | new ImportPathChecker(reporter, config, fileName),
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/lib/rules/naming/const-name-snakecase.js:
--------------------------------------------------------------------------------
1 | const BaseChecker = require('../base-checker')
2 | const naming = require('../../common/identifier-naming')
3 |
4 | const ruleId = 'const-name-snakecase'
5 | const meta = {
6 | type: 'naming',
7 |
8 | docs: {
9 | description:
10 | 'Constant name must be in capitalized SNAKE_CASE. (Does not check IMMUTABLES, use immutable-vars-naming)',
11 | category: 'Style Guide Rules',
12 | },
13 |
14 | recommended: true,
15 | defaultSetup: 'warn',
16 |
17 | schema: null,
18 | }
19 |
20 | class ConstNameSnakecaseChecker extends BaseChecker {
21 | constructor(reporter) {
22 | super(reporter, ruleId, meta)
23 | }
24 |
25 | VariableDeclaration(node) {
26 | if (node.isDeclaredConst) {
27 | this.validateConstantName(node)
28 | }
29 | }
30 |
31 | validateConstantName(variable) {
32 | if (naming.isNotUpperSnakeCase(variable.name)) {
33 | this.error(variable, 'Constant name must be in capitalized SNAKE_CASE')
34 | }
35 | }
36 | }
37 |
38 | module.exports = ConstNameSnakecaseChecker
39 |
--------------------------------------------------------------------------------
/lib/rules/naming/func-name-mixedcase.js:
--------------------------------------------------------------------------------
1 | const BaseChecker = require('../base-checker')
2 | const naming = require('../../common/identifier-naming')
3 |
4 | const ruleId = 'func-name-mixedcase'
5 | const meta = {
6 | type: 'naming',
7 |
8 | docs: {
9 | description: 'Function name must be in mixedCase.',
10 | category: 'Style Guide Rules',
11 | },
12 |
13 | recommended: true,
14 | defaultSetup: 'warn',
15 |
16 | schema: null,
17 | }
18 |
19 | class FuncNameMixedcaseChecker extends BaseChecker {
20 | constructor(reporter) {
21 | super(reporter, ruleId, meta)
22 | }
23 |
24 | FunctionDefinition(node) {
25 | if (naming.isNotMixedCase(node.name) && !node.isConstructor) {
26 | this.error(node, 'Function name must be in mixedCase')
27 | }
28 | }
29 | }
30 |
31 | module.exports = FuncNameMixedcaseChecker
32 |
--------------------------------------------------------------------------------
/lib/rules/naming/func-param-name-mixedcase.js:
--------------------------------------------------------------------------------
1 | const BaseChecker = require('../base-checker')
2 | const naming = require('../../common/identifier-naming')
3 |
4 | const ruleId = 'func-param-name-mixedcase'
5 | const meta = {
6 | type: 'naming',
7 |
8 | docs: {
9 | description: 'Function param name must be in mixedCase.',
10 | category: 'Style Guide Rules',
11 | },
12 |
13 | recommended: false,
14 | defaultSetup: 'warn',
15 |
16 | schema: null,
17 | }
18 |
19 | class FunctionParamNameMixedcaseChecker extends BaseChecker {
20 | constructor(reporter) {
21 | super(reporter, ruleId, meta)
22 | }
23 |
24 | EventDefinition(node) {
25 | this.FunctionDefinition(node)
26 | }
27 |
28 | FunctionDefinition(node) {
29 | node.parameters.forEach((parameter) => {
30 | if (naming.isNotMixedCase(parameter.name)) {
31 | this.error(parameter, 'Function param name must be in mixedCase')
32 | }
33 | })
34 | }
35 | }
36 |
37 | module.exports = FunctionParamNameMixedcaseChecker
38 |
--------------------------------------------------------------------------------
/lib/rules/naming/modifier-name-mixedcase.js:
--------------------------------------------------------------------------------
1 | const BaseChecker = require('../base-checker')
2 | const naming = require('../../common/identifier-naming')
3 |
4 | const ruleId = 'modifier-name-mixedcase'
5 | const meta = {
6 | type: 'naming',
7 |
8 | docs: {
9 | description: 'Modifier name must be in mixedCase.',
10 | category: 'Style Guide Rules',
11 | },
12 |
13 | recommended: false,
14 | defaultSetup: 'warn',
15 |
16 | schema: null,
17 | }
18 |
19 | class ModifierNameMixedcase extends BaseChecker {
20 | constructor(reporter) {
21 | super(reporter, ruleId, meta)
22 | }
23 |
24 | ModifierDefinition(node) {
25 | if (naming.isNotMixedCase(node.name)) {
26 | this.error(node, 'Modifier name must be in mixedCase')
27 | }
28 | }
29 | }
30 |
31 | module.exports = ModifierNameMixedcase
32 |
--------------------------------------------------------------------------------
/lib/rules/naming/use-forbidden-name.js:
--------------------------------------------------------------------------------
1 | const BaseChecker = require('../base-checker')
2 |
3 | const FORBIDDEN_NAMES = ['I', 'l', 'O']
4 |
5 | const ruleId = 'use-forbidden-name'
6 | const meta = {
7 | type: 'naming',
8 |
9 | docs: {
10 | description: `Avoid to use letters 'I', 'l', 'O' as identifiers.`,
11 | category: 'Style Guide Rules',
12 | },
13 |
14 | recommended: true,
15 | defaultSetup: 'warn',
16 |
17 | schema: null,
18 | }
19 |
20 | class UseForbiddenNameChecker extends BaseChecker {
21 | constructor(reporter) {
22 | super(reporter, ruleId, meta)
23 | }
24 |
25 | VariableDeclaration(node) {
26 | if (FORBIDDEN_NAMES.includes(node.name)) {
27 | this.error(node, "Avoid to use letters 'I', 'l', 'O' as identifiers")
28 | }
29 | }
30 | }
31 |
32 | module.exports = UseForbiddenNameChecker
33 |
--------------------------------------------------------------------------------
/lib/rules/naming/var-name-mixedcase.js:
--------------------------------------------------------------------------------
1 | const BaseChecker = require('../base-checker')
2 | const naming = require('../../common/identifier-naming')
3 |
4 | const ruleId = 'var-name-mixedcase'
5 | const meta = {
6 | type: 'naming',
7 |
8 | docs: {
9 | description: `Variable names must be in mixedCase. (Does not check IMMUTABLES, use immutable-vars-naming)`,
10 | category: 'Style Guide Rules',
11 | },
12 |
13 | recommended: true,
14 | defaultSetup: 'warn',
15 |
16 | schema: null,
17 | }
18 |
19 | class VarNameMixedcaseChecker extends BaseChecker {
20 | constructor(reporter) {
21 | super(reporter, ruleId, meta)
22 | }
23 |
24 | VariableDeclaration(node) {
25 | if (!node.isDeclaredConst && !node.isImmutable) {
26 | this.validateVariablesName(node)
27 | }
28 | }
29 |
30 | validateVariablesName(node) {
31 | if (naming.isNotMixedCase(node.name)) {
32 | this.error(node, 'Variable name must be in mixedCase')
33 | }
34 | }
35 | }
36 |
37 | module.exports = VarNameMixedcaseChecker
38 |
--------------------------------------------------------------------------------
/lib/rules/order/imports-on-top.js:
--------------------------------------------------------------------------------
1 | const BaseChecker = require('../base-checker')
2 |
3 | const ruleId = 'imports-on-top'
4 | const meta = {
5 | type: 'order',
6 |
7 | docs: {
8 | description: `Import statements must be on top.`,
9 | category: 'Style Guide Rules',
10 | },
11 |
12 | recommended: true,
13 | defaultSetup: 'warn',
14 |
15 | schema: null,
16 | }
17 |
18 | class ImportsOnTopChecker extends BaseChecker {
19 | constructor(reporter) {
20 | super(reporter, ruleId, meta)
21 | }
22 |
23 | SourceUnit(node) {
24 | let hasContractDef = false
25 | for (let i = 0; node.children && i < node.children.length; i += 1) {
26 | const curItem = node.children[i]
27 |
28 | if (curItem.type === 'ContractDefinition') {
29 | hasContractDef = true
30 | }
31 |
32 | if (hasContractDef && curItem.type === 'ImportDirective') {
33 | this._error(curItem)
34 | }
35 | }
36 | }
37 |
38 | _error(node) {
39 | this.error(node, 'Import statements must be on top')
40 | }
41 | }
42 |
43 | module.exports = ImportsOnTopChecker
44 |
--------------------------------------------------------------------------------
/lib/rules/order/index.js:
--------------------------------------------------------------------------------
1 | const ImportsOnTopChecker = require('./imports-on-top')
2 | const VisibilityModifierOrderChecker = require('./visibility-modifier-order')
3 | const OrderingChecker = require('./ordering')
4 | const ImportsOrderChecker = require('./imports-order')
5 |
6 | module.exports = function order(reporter, tokens) {
7 | return [
8 | new ImportsOnTopChecker(reporter),
9 | new VisibilityModifierOrderChecker(reporter, tokens),
10 | new OrderingChecker(reporter),
11 | new ImportsOrderChecker(reporter),
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/lib/rules/security/avoid-call-value.js:
--------------------------------------------------------------------------------
1 | const BaseChecker = require('../base-checker')
2 |
3 | const ruleId = 'avoid-call-value'
4 | const meta = {
5 | type: 'security',
6 |
7 | docs: {
8 | description: `Avoid to use ".call.value()()".`,
9 | category: 'Security Rules',
10 | },
11 |
12 | recommended: true,
13 | defaultSetup: 'warn',
14 |
15 | schema: null,
16 | }
17 |
18 | class AvoidCallValueChecker extends BaseChecker {
19 | constructor(reporter) {
20 | super(reporter, ruleId, meta)
21 | }
22 |
23 | MemberAccess(node) {
24 | this.validateCallValue(node)
25 | }
26 |
27 | validateCallValue(node) {
28 | if (node.memberName === 'value' && node.expression.memberName === 'call') {
29 | this.error(node, 'Avoid to use ".call.value()()"')
30 | }
31 | }
32 | }
33 |
34 | module.exports = AvoidCallValueChecker
35 |
--------------------------------------------------------------------------------
/lib/rules/security/avoid-sha3.js:
--------------------------------------------------------------------------------
1 | const BaseChecker = require('../base-checker')
2 |
3 | const ruleId = 'avoid-sha3'
4 | const meta = {
5 | type: 'security',
6 |
7 | docs: {
8 | description: `Use "keccak256" instead of deprecated "sha3".`,
9 | category: 'Security Rules',
10 | notes: [
11 | {
12 | note: 'Solhint allows this rule to automatically fix the code with `--fix` option',
13 | },
14 | ],
15 | },
16 |
17 | recommended: true,
18 | defaultSetup: 'warn',
19 | fixable: true,
20 |
21 | schema: null,
22 | }
23 |
24 | class AvoidSha3Checker extends BaseChecker {
25 | constructor(reporter) {
26 | super(reporter, ruleId, meta)
27 | }
28 |
29 | Identifier(node) {
30 | if (node.name === 'sha3') {
31 | this.error(node, 'Use "keccak256" instead of deprecated "sha3"', (fixer) =>
32 | fixer.replaceTextRange(node.range, 'keccak256')
33 | )
34 | }
35 | }
36 | }
37 |
38 | module.exports = AvoidSha3Checker
39 |
--------------------------------------------------------------------------------
/lib/rules/security/avoid-suicide.js:
--------------------------------------------------------------------------------
1 | const BaseChecker = require('../base-checker')
2 |
3 | const ruleId = 'avoid-suicide'
4 | const meta = {
5 | type: 'security',
6 |
7 | docs: {
8 | description: `Use "selfdestruct" instead of deprecated "suicide".`,
9 | category: 'Security Rules',
10 | },
11 |
12 | recommended: true,
13 | defaultSetup: 'warn',
14 | fixable: true,
15 | schema: null,
16 | }
17 |
18 | class AvoidSuicideChecker extends BaseChecker {
19 | constructor(reporter) {
20 | super(reporter, ruleId, meta)
21 | }
22 |
23 | FunctionCall(node) {
24 | if (node.expression.type === 'Identifier' && node.expression.name === 'suicide') {
25 | this.error(
26 | node,
27 | 'Use "selfdestruct" instead of deprecated "suicide"',
28 | this.fixStatement(node)
29 | )
30 | }
31 | }
32 |
33 | fixStatement(node) {
34 | let stringToPut = 'selfdestruct()'
35 |
36 | if (node.arguments.length > 0) {
37 | stringToPut = 'selfdestruct(' + node.arguments[0].name + ')'
38 | }
39 |
40 | return (fixer) => fixer.replaceTextRange(node.range, stringToPut)
41 | }
42 | }
43 |
44 | module.exports = AvoidSuicideChecker
45 |
--------------------------------------------------------------------------------
/lib/rules/security/avoid-throw.js:
--------------------------------------------------------------------------------
1 | const BaseChecker = require('../base-checker')
2 |
3 | const ruleId = 'avoid-throw'
4 | const meta = {
5 | type: 'security',
6 |
7 | docs: {
8 | description: `"throw" is deprecated, avoid to use it.`,
9 | category: 'Security Rules',
10 | notes: [
11 | {
12 | note: 'Solhint allows this rule to automatically fix the code with `--fix` option',
13 | },
14 | ],
15 | },
16 |
17 | recommended: true,
18 | defaultSetup: 'warn',
19 | fixable: true,
20 |
21 | schema: null,
22 | }
23 |
24 | class AvoidThrowChecker extends BaseChecker {
25 | constructor(reporter) {
26 | super(reporter, ruleId, meta)
27 | }
28 |
29 | ThrowStatement(node) {
30 | this.error(node, '"throw" is deprecated, avoid to use it', (fixer) =>
31 | // we don't use just `node.range` because ThrowStatement includes the semicolon and the spaces before it
32 | // we know that node.range[0] is the 't' of throw
33 | // we're also pretty sure that 'throw' has 5 letters
34 | fixer.replaceTextRange([node.range[0], node.range[0] + 5], 'revert();')
35 | )
36 | }
37 | }
38 |
39 | module.exports = AvoidThrowChecker
40 |
--------------------------------------------------------------------------------
/lib/rules/security/avoid-tx-origin.js:
--------------------------------------------------------------------------------
1 | const BaseChecker = require('../base-checker')
2 |
3 | const ruleId = 'avoid-tx-origin'
4 | const meta = {
5 | type: 'security',
6 |
7 | docs: {
8 | description: `Avoid to use tx.origin.`,
9 | category: 'Security Rules',
10 | },
11 |
12 | recommended: true,
13 | defaultSetup: 'warn',
14 |
15 | schema: null,
16 | }
17 |
18 | class AvoidTxOriginChecker extends BaseChecker {
19 | constructor(reporter) {
20 | super(reporter, ruleId, meta)
21 | }
22 |
23 | MemberAccess(node) {
24 | if (node.expression.name === 'tx' && node.memberName === 'origin') {
25 | this.error(node, 'Avoid to use tx.origin')
26 | }
27 | }
28 | }
29 |
30 | module.exports = AvoidTxOriginChecker
31 |
--------------------------------------------------------------------------------
/lib/rules/security/no-complex-fallback.js:
--------------------------------------------------------------------------------
1 | const BaseChecker = require('../base-checker')
2 | const { isFallbackFunction } = require('../../common/ast-types')
3 |
4 | const ruleId = 'no-complex-fallback'
5 | const meta = {
6 | type: 'security',
7 |
8 | docs: {
9 | description: `Fallback function must be simple.`,
10 | category: 'Security Rules',
11 | },
12 |
13 | recommended: true,
14 | defaultSetup: 'warn',
15 |
16 | schema: null,
17 | }
18 |
19 | class NoComplexFallbackChecker extends BaseChecker {
20 | constructor(reporter) {
21 | super(reporter, ruleId, meta)
22 | }
23 |
24 | FunctionDefinition(node) {
25 | if (isFallbackFunction(node)) {
26 | if (node.body.statements.length >= 2) {
27 | this.warn(node, 'Fallback function must be simple')
28 | }
29 | }
30 | }
31 | }
32 |
33 | module.exports = NoComplexFallbackChecker
34 |
--------------------------------------------------------------------------------
/lib/rules/security/no-inline-assembly.js:
--------------------------------------------------------------------------------
1 | const BaseChecker = require('../base-checker')
2 |
3 | const ruleId = 'no-inline-assembly'
4 | const meta = {
5 | type: 'security',
6 |
7 | docs: {
8 | description: `Avoid to use inline assembly. It is acceptable only in rare cases.`,
9 | category: 'Security Rules',
10 | },
11 |
12 | recommended: true,
13 | defaultSetup: 'warn',
14 |
15 | schema: null,
16 | }
17 |
18 | class NoInlineAssemblyChecker extends BaseChecker {
19 | constructor(reporter) {
20 | super(reporter, ruleId, meta)
21 | }
22 |
23 | InlineAssemblyStatement(node) {
24 | this.error(node)
25 | }
26 |
27 | error(node) {
28 | this.warn(node, 'Avoid to use inline assembly. It is acceptable only in rare cases')
29 | }
30 | }
31 |
32 | module.exports = NoInlineAssemblyChecker
33 |
--------------------------------------------------------------------------------
/lib/rules/security/not-rely-on-block-hash.js:
--------------------------------------------------------------------------------
1 | const BaseChecker = require('../base-checker')
2 |
3 | const ruleId = 'not-rely-on-block-hash'
4 | const meta = {
5 | type: 'security',
6 |
7 | docs: {
8 | description: `Do not rely on "block.blockhash". Miners can influence its value.`,
9 | category: 'Security Rules',
10 | },
11 |
12 | recommended: true,
13 | defaultSetup: 'warn',
14 |
15 | schema: null,
16 | }
17 |
18 | class NotRelyOnBlockHashChecker extends BaseChecker {
19 | constructor(reporter) {
20 | super(reporter, ruleId, meta)
21 | }
22 |
23 | MemberAccess(node) {
24 | if (node.expression.name === 'block' && node.memberName === 'blockhash') {
25 | this._warn(node)
26 | }
27 | }
28 |
29 | _warn(node) {
30 | this.warn(node, 'Do not rely on "block.blockhash". Miners can influence its value.')
31 | }
32 | }
33 |
34 | module.exports = NotRelyOnBlockHashChecker
35 |
--------------------------------------------------------------------------------
/lib/rules/security/not-rely-on-time.js:
--------------------------------------------------------------------------------
1 | const BaseChecker = require('../base-checker')
2 |
3 | const ruleId = 'not-rely-on-time'
4 | const meta = {
5 | type: 'security',
6 |
7 | docs: {
8 | description: `Avoid making time-based decisions in your business logic.`,
9 | category: 'Security Rules',
10 | },
11 |
12 | recommended: false,
13 | defaultSetup: 'warn',
14 |
15 | schema: null,
16 | }
17 |
18 | class NotRelyOnTimeChecker extends BaseChecker {
19 | constructor(reporter) {
20 | super(reporter, ruleId, meta)
21 | }
22 |
23 | Identifier(node) {
24 | if (node.name === 'now') {
25 | this._warn(node)
26 | }
27 | }
28 |
29 | MemberAccess(node) {
30 | if (node.expression.name === 'block' && node.memberName === 'timestamp') {
31 | this._warn(node)
32 | }
33 | }
34 |
35 | _warn(node) {
36 | this.warn(node, 'Avoid making time-based decisions in your business logic')
37 | }
38 | }
39 |
40 | module.exports = NotRelyOnTimeChecker
41 |
--------------------------------------------------------------------------------
/lib/rules/security/state-visibility.js:
--------------------------------------------------------------------------------
1 | const BaseChecker = require('../base-checker')
2 |
3 | const ruleId = 'state-visibility'
4 | const meta = {
5 | type: 'security',
6 |
7 | docs: {
8 | description: `Explicitly mark visibility of state.`,
9 | category: 'Security Rules',
10 | },
11 |
12 | recommended: true,
13 | defaultSetup: 'warn',
14 |
15 | schema: null,
16 | }
17 |
18 | class StateVisibilityChecker extends BaseChecker {
19 | constructor(reporter) {
20 | super(reporter, ruleId, meta)
21 | }
22 |
23 | StateVariableDeclaration(node) {
24 | if (node.variables.some(({ visibility }) => visibility === 'default')) {
25 | this.warn(node, 'Explicitly mark visibility of state')
26 | }
27 | }
28 | }
29 |
30 | module.exports = StateVisibilityChecker
31 |
--------------------------------------------------------------------------------
/lib/tree-listener.js:
--------------------------------------------------------------------------------
1 | class SecurityErrorListener {
2 | constructor(checkers) {
3 | this.listenersMap = {}
4 |
5 | checkers.forEach((i) => this.addChecker(i))
6 | }
7 |
8 | addChecker(newChecker) {
9 | const listenerMethods = Object.getOwnPropertyNames(newChecker.constructor.prototype)
10 |
11 | const usedListenerMethods = listenerMethods.filter((i) => /^[A-Z]/.test(i))
12 |
13 | usedListenerMethods.forEach((methodName) => this.addNewListener(methodName, newChecker))
14 |
15 | usedListenerMethods.forEach((methodName) => {
16 | this[methodName] = this.notifyListenersOn(methodName)
17 | })
18 | }
19 |
20 | listenersFor(name) {
21 | return this.listenersMap[name] || []
22 | }
23 |
24 | addNewListener(methodName, checker) {
25 | const method = checker[methodName].bind(checker)
26 | const listeners = this.listenersFor(methodName)
27 | this.listenersMap[methodName] = listeners.concat(method)
28 | }
29 |
30 | notifyListenersOn(methodName) {
31 | return (ctx) => this.listenersFor(methodName).forEach((fn) => quite(fn)(ctx))
32 | }
33 | }
34 |
35 | function quite(fn) {
36 | return (...args) => {
37 | try {
38 | if (fn) {
39 | fn.call(fn, ...args)
40 | }
41 | } catch (err) {
42 | // console.log(err);
43 | }
44 | }
45 | }
46 |
47 | module.exports = SecurityErrorListener
48 |
--------------------------------------------------------------------------------
/scripts/check-changes.js:
--------------------------------------------------------------------------------
1 | const { execSync } = require('child_process')
2 |
3 | function changed() {
4 | try {
5 | // Run Git commands to check for changes in the lib/rules directory
6 | const diffIndex = execSync('git diff-index --name-only -B -R -M -C HEAD lib/rules')
7 | .toString()
8 | .trim()
9 | const lsFiles = execSync('git ls-files -t -o -m lib/rules').toString().trim()
10 |
11 | // Return true if there are changes
12 | return diffIndex !== '' || lsFiles !== ''
13 | } catch (error) {
14 | console.error('Error checking for changes:', error)
15 | return false
16 | }
17 | }
18 |
19 | if (changed()) {
20 | try {
21 | // Run npm commands if there are changes
22 | execSync('npm run generate-rulesets', { stdio: 'inherit' })
23 | execSync('npm run docs', { stdio: 'inherit' })
24 | } catch (error) {
25 | console.error('Error running npm commands:', error)
26 | process.exit(1)
27 | }
28 | } else {
29 | console.log('No changes detected in lib/rules.')
30 | }
31 |
--------------------------------------------------------------------------------
/scripts/generate-rulesets.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs')
2 |
3 | const { loadRules } = require('../lib/load-rules')
4 |
5 | const rulesConstants = loadRules()
6 | const allRules = {}
7 | const recommendedRules = {}
8 |
9 | rulesConstants.forEach((rule) => {
10 | if (!rule.meta.deprecated) {
11 | allRules[rule.ruleId] = rule.meta.defaultSetup
12 | }
13 | if (!rule.meta.deprecated && rule.meta.recommended) {
14 | recommendedRules[rule.ruleId] = rule.meta.defaultSetup
15 | }
16 | })
17 |
18 | function writeRuleset(ruleset, filename) {
19 | const code = `/*
20 | * WARNING: This file is autogenerated using the scripts/generate-rulesets.js
21 | * script. Do not edit manually.
22 | */
23 |
24 | module.exports = Object.freeze(${JSON.stringify({ rules: ruleset }, null, 2)})
25 | `
26 |
27 | fs.writeFileSync(`./conf/rulesets/solhint-${filename}.js`, code, 'utf8')
28 | }
29 |
30 | writeRuleset(allRules, 'all')
31 | writeRuleset(recommendedRules, 'recommended')
32 |
--------------------------------------------------------------------------------
/solhint-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/protofire/solhint/4dd80890cff0d00051f67f8133877f26482588bb/solhint-icon.png
--------------------------------------------------------------------------------
/solhint.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/protofire/solhint/4dd80890cff0d00051f67f8133877f26482588bb/solhint.png
--------------------------------------------------------------------------------
/test/common/apply-fixes.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 |
3 | const applyFixes = require('../../lib/apply-fixes')
4 |
5 | describe('applyFixes', () => {
6 | it('should work when there are no reports', () => {
7 | const inputSrc = 'contract Foo {}'
8 | const fixes = []
9 |
10 | const { fixed } = applyFixes(fixes, inputSrc)
11 |
12 | assert.equal(fixed, false)
13 | })
14 |
15 | it('should work for a single replace', () => {
16 | const inputSrc = `
17 | contract Foo {
18 | function foo() {
19 | throw;
20 | }
21 | }`.trim()
22 |
23 | const fixes = [
24 | {
25 | range: [38, 42],
26 | text: 'revert()',
27 | },
28 | ]
29 |
30 | const { fixed, output } = applyFixes(fixes, inputSrc)
31 |
32 | assert.equal(fixed, true)
33 | assert.equal(
34 | output,
35 | `
36 | contract Foo {
37 | function foo() {
38 | revert();
39 | }
40 | }`.trim()
41 | )
42 | })
43 |
44 | it('should work for two fixes', () => {
45 | const inputSrc = `
46 | contract Foo {
47 | function foo() {
48 | throw;
49 | throw;
50 | }
51 | }`.trim()
52 |
53 | const fixes = [
54 | {
55 | range: [38, 42],
56 | text: 'revert()',
57 | },
58 | {
59 | range: [49, 53],
60 | text: 'revert()',
61 | },
62 | ]
63 |
64 | const { fixed, output } = applyFixes(fixes, inputSrc)
65 |
66 | assert.equal(fixed, true)
67 | assert.equal(
68 | output,
69 | `
70 | contract Foo {
71 | function foo() {
72 | revert();
73 | revert();
74 | }
75 | }`.trim()
76 | )
77 | })
78 | })
79 |
--------------------------------------------------------------------------------
/test/common/config-file.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const { loadConfig } = require('../../lib/config/config-file')
3 |
4 | describe('Config file', () => {
5 | it(`should throw an error if the config file doesn't exist`, () => {
6 | assert.throws(
7 | () => loadConfig('.solhint.json'),
8 | /^Error: The config file passed as a parameter does not exist$/
9 | )
10 | })
11 |
12 | it(`should load the config file if exist`, () => {
13 | const loadedConfig = loadConfig('./test/helpers/solhint_config_test.json')
14 |
15 | const loadedConfigFileExpected = {
16 | extends: ['solhint:recommended'],
17 | }
18 |
19 | assert.deepStrictEqual(loadedConfig, loadedConfigFileExpected)
20 | })
21 | })
22 |
--------------------------------------------------------------------------------
/test/common/config-validator.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const _ = require('lodash')
3 | const {
4 | validate,
5 | validSeverityMap,
6 | defaultSchemaValueForRules,
7 | } = require('../../lib/config/config-validator')
8 |
9 | describe('Config validator', () => {
10 | it('should check validSeverityMap', () => {
11 | assert.deepStrictEqual(validSeverityMap, ['error', 'warn'])
12 | })
13 |
14 | it('should check defaultSchemaValueForRules', () => {
15 | assert.deepStrictEqual(defaultSchemaValueForRules, {
16 | oneOf: [{ type: 'string', enum: ['error', 'warn', 'off'] }, { const: false }],
17 | })
18 | })
19 |
20 | it('should validate config', () => {
21 | const config = {
22 | extends: [],
23 | rules: {
24 | 'avoid-throw': 'off',
25 | indent: ['error', 2],
26 | },
27 | }
28 | assert.deepStrictEqual(_.isUndefined(validate(config)), true)
29 | })
30 |
31 | it('should throw an error with wrong config', () => {
32 | const config = {
33 | test: [],
34 | rules: {
35 | 'avoid-throw': 'off',
36 | indent: ['error', 2],
37 | },
38 | }
39 | assert.throws(() => validate(config), Error)
40 | })
41 |
42 | it('should work with an empty config', () => {
43 | const config = {}
44 |
45 | validate(config) // should not throw
46 | })
47 | })
48 |
--------------------------------------------------------------------------------
/test/common/contract-builder.js:
--------------------------------------------------------------------------------
1 | const { times } = require('lodash')
2 |
3 | function contractWith(code) {
4 | return `
5 | pragma solidity 0.4.4;
6 |
7 |
8 | contract A {
9 | ${code}
10 | }
11 | `
12 | }
13 |
14 | function libraryWith(code) {
15 | return `
16 | pragma solidity 0.4.4;
17 |
18 |
19 | library A {
20 | ${code}
21 | }
22 | `
23 | }
24 |
25 | function funcWith(statements) {
26 | return contractWith(`
27 | function b() public {
28 | ${statements}
29 | }
30 | `)
31 | }
32 |
33 | function modifierWith(statements) {
34 | return contractWith(`
35 | modifier b() {
36 | ${statements}
37 | }
38 | `)
39 | }
40 |
41 | function multiLine(...args) {
42 | return args.join('\n')
43 | }
44 |
45 | function contractWithPrettier(code) {
46 | return `pragma solidity 0.4.4;
47 |
48 | contract A {
49 | ${code}
50 | }
51 | `
52 | }
53 |
54 | function stateDef(count) {
55 | return repeatLines(' uint private a;', count)
56 | }
57 |
58 | function constantDef(count) {
59 | return repeatLines(' uint private constant TEST = 1;', count)
60 | }
61 |
62 | function repeatLines(line, count) {
63 | return times(count)
64 | .map(() => line)
65 | .join('\n')
66 | }
67 |
68 | module.exports = {
69 | contractWith,
70 | libraryWith,
71 | funcWith,
72 | modifierWith,
73 | multiLine,
74 | contractWithPrettier,
75 | stateDef,
76 | constantDef,
77 | repeatLines,
78 | }
79 |
--------------------------------------------------------------------------------
/test/common/errors.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const { ConfigMissingError } = require('../../lib/common/errors')
3 |
4 | describe('errors', () => {
5 | it('should throw a ConfigMissingError and match the message', () => {
6 | const ThrowError = () => {
7 | throw new ConfigMissingError('config_example.json')
8 | }
9 |
10 | assert.throws(ThrowError, ConfigMissingError)
11 | assert.throws(ThrowError, /Failed to load config "config_example.json" to extend from.$/)
12 | })
13 |
14 | it('should throw a ConfigMissingError and match the default message', () => {
15 | const ThrowError = () => {
16 | throw new ConfigMissingError()
17 | }
18 |
19 | assert.throws(ThrowError, ConfigMissingError)
20 | assert.throws(ThrowError, /Failed to load a solhint's config file.$/)
21 | })
22 | })
23 |
--------------------------------------------------------------------------------
/test/common/load-rules.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const _ = require('lodash')
3 | const { loadRule, loadRules } = require('../../lib/load-rules')
4 |
5 | describe('Load Rules', () => {
6 | it('should load all rules', () => {
7 | const rules = loadRules()
8 |
9 | for (const rule of rules) {
10 | assert.equal(typeof rule, 'object')
11 | assert.equal(_.has(rule, 'meta'), true)
12 | assert.equal(_.has(rule, 'ruleId'), true)
13 | assert.equal(_.has(rule.meta, 'type'), true)
14 | assert.equal(_.has(rule.meta, 'docs'), true)
15 | assert.equal(_.has(rule.meta, 'recommended'), true)
16 | assert.equal(_.has(rule.meta, 'defaultSetup'), true)
17 | assert.equal(_.has(rule.meta, 'schema'), true)
18 | }
19 | })
20 |
21 | it('should load a single rule', () => {
22 | const rule = loadRule('func-param-name-mixedcase')
23 |
24 | assert.equal(typeof rule, 'object')
25 | assert.equal(_.has(rule, 'meta'), true)
26 | assert.equal(_.has(rule, 'ruleId'), true)
27 | assert.equal(_.has(rule.meta, 'type'), true)
28 | assert.equal(_.has(rule.meta, 'docs'), true)
29 | assert.equal(_.has(rule.meta, 'recommended'), true)
30 | assert.equal(_.has(rule.meta, 'defaultSetup'), true)
31 | assert.equal(_.has(rule.meta, 'schema'), true)
32 | })
33 |
34 | it('should not load a single rule', () => {
35 | const rule = loadRule('foo')
36 |
37 | assert.equal(_.isUndefined(rule), true)
38 | })
39 | })
40 |
--------------------------------------------------------------------------------
/test/common/utils.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs')
2 | const os = require('os')
3 | const path = require('path')
4 |
5 | function tmpFilePath() {
6 | const tempDirPath = os.tmpdir()
7 | return path.resolve(tempDirPath, 'test.sol')
8 | }
9 |
10 | function storeAsFile(code) {
11 | const filePath = tmpFilePath()
12 |
13 | fs.writeFileSync(filePath, code, 'utf-8')
14 |
15 | return filePath
16 | }
17 |
18 | function removeTmpFiles() {
19 | try {
20 | fs.unlinkSync(tmpFilePath())
21 | } catch (err) {
22 | // console.log(err);
23 | }
24 | }
25 |
26 | module.exports = { tmpFilePath, storeAsFile, removeTmpFiles }
27 |
--------------------------------------------------------------------------------
/test/fixtures/align/array_declaration.js:
--------------------------------------------------------------------------------
1 | const { contractWith } = require('../../common/contract-builder')
2 |
3 | module.exports = contractWith('uint[][] private a;')
4 |
--------------------------------------------------------------------------------
/test/fixtures/align/array_declaration_with_spaces.js:
--------------------------------------------------------------------------------
1 | const { contractWith } = require('../../common/contract-builder')
2 |
3 | module.exports = contractWith('uint [] [] private a;')
4 |
--------------------------------------------------------------------------------
/test/fixtures/align/correctly_aligned_function_brackets.js:
--------------------------------------------------------------------------------
1 | const { contractWith } = require('../../common/contract-builder')
2 |
3 | module.exports = contractWith(`
4 | function a (
5 | uint a
6 | )
7 | public
8 | {
9 | continue;
10 | }
11 | `)
12 |
--------------------------------------------------------------------------------
/test/fixtures/align/correctly_indented_contract.js:
--------------------------------------------------------------------------------
1 | const { multiLine } = require('../../common/contract-builder')
2 |
3 | module.exports = multiLine(
4 | 'contract A { ',
5 | ' function a() public view returns (uint, uint) {',
6 | ' return (1, 2); ',
7 | ' } ',
8 | ' ',
9 | ' function b() public view returns (uint, uint) {',
10 | ' ( ',
11 | ' uint c, ',
12 | ' uint d ',
13 | ' ) = a(); ',
14 | ' return (c, d); ',
15 | ' } ',
16 | '} '
17 | )
18 |
--------------------------------------------------------------------------------
/test/fixtures/align/expression_with_mixed_tabs_and_spaces.js:
--------------------------------------------------------------------------------
1 | module.exports = ' \t import "lib.sol";'
2 |
--------------------------------------------------------------------------------
/test/fixtures/align/expressions_with_correct_comma_align.js:
--------------------------------------------------------------------------------
1 | const { funcWith, contractWith } = require('../../common/contract-builder')
2 |
3 | module.exports = [
4 | funcWith('var (a, b,) = test1.test2(); a + b;'),
5 | funcWith('test(1, 2, b);'),
6 | contractWith('function b(uint a, uintc) public {}'),
7 | contractWith('enum A {Test1, Test2}'),
8 | funcWith('var (a, , , b) = test1.test2(); a + b;'),
9 | ]
10 |
--------------------------------------------------------------------------------
/test/fixtures/align/expressions_with_correct_indents.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | 'new TrustedContract',
3 | 'myArray[5]',
4 | 'myFunc(1, 2, 3)',
5 | 'emit myEvent(1, 2, 3)',
6 | 'myFunc.call(1)',
7 | 'a = (b + c)',
8 | 'a = b + 1',
9 | 'a += 1',
10 | 'a == b',
11 | '1**2',
12 | 'a && b',
13 | 'a > b ? a : b',
14 | '!a',
15 | 'a++',
16 | 'a += 1',
17 | 'a += (b + c) * d',
18 | 'bytesStringTrimmed[j] = bytesString[j]',
19 | ]
20 |
--------------------------------------------------------------------------------
/test/fixtures/align/expressions_with_correct_semicolon_align.js:
--------------------------------------------------------------------------------
1 | module.exports = ['var (a, b,) = test1.test2(); a + b;', 'test(1, 2, b);']
2 |
--------------------------------------------------------------------------------
/test/fixtures/align/expressions_with_incorrect_comma_align.js:
--------------------------------------------------------------------------------
1 | const { funcWith, contractWith } = require('../../common/contract-builder')
2 |
3 | module.exports = [
4 | funcWith('var (a,b) = test1.test2(); a + b;'),
5 | funcWith('test(1,2, b);'),
6 | funcWith('test(1,/* test */ 2, b);'),
7 | contractWith('function b(uint a,uintc) public {}'),
8 | funcWith('test(1, 2 , b);'),
9 | funcWith('var (a, ,, b) = test1.test2(); a + b;'),
10 | ]
11 |
--------------------------------------------------------------------------------
/test/fixtures/align/expressions_with_incorrect_indents.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | 'new TrustedContract',
3 | 'myArray[ 5 ]',
4 | 'myArray/* test */[5]',
5 | 'myFunc( 1, 2, 3 )',
6 | 'myFunc. call(1)',
7 | 'a = ( b + c )',
8 | 'a=b + 1',
9 | 'a+=1',
10 | 'a ==b',
11 | '1** 2',
12 | 'a &&b',
13 | 'a > b ?a : b',
14 | '! a',
15 | 'a ++',
16 | 'a +=1',
17 | ]
18 |
--------------------------------------------------------------------------------
/test/fixtures/align/expressions_with_incorrect_semicolon_align.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | 'var (a, b) = test1.test2() ; a + b;',
3 | 'test(1, 2, b) ;',
4 | 'test(1, 2, b)/* test */;',
5 | 'for ( ;;) {}',
6 | 'for (i = 0; ;) {}',
7 | 'for ( ; a < b;) {}',
8 | ]
9 |
--------------------------------------------------------------------------------
/test/fixtures/align/incorrectly_aligned_forloop_brackets.js:
--------------------------------------------------------------------------------
1 | const { funcWith } = require('../../common/contract-builder')
2 |
3 | module.exports = funcWith(`
4 | for (uint i = 0; i < a; i += 1)
5 | {
6 | continue;
7 | }
8 | `)
9 |
--------------------------------------------------------------------------------
/test/fixtures/align/incorrectly_aligned_function_brackets.js:
--------------------------------------------------------------------------------
1 | const { contractWith } = require('../../common/contract-builder')
2 |
3 | module.exports = contractWith(`
4 | function a (uint a) public{
5 | continue;
6 | }
7 | `)
8 |
--------------------------------------------------------------------------------
/test/fixtures/align/incorrectly_indented_contract.js:
--------------------------------------------------------------------------------
1 | const { multiLine } = require('../../common/contract-builder')
2 |
3 | module.exports = multiLine(
4 | ' contract A { ',
5 | ' uint private a; ',
6 | ' } '
7 | )
8 |
--------------------------------------------------------------------------------
/test/fixtures/align/statements_with_correct_indents.js:
--------------------------------------------------------------------------------
1 | const { multiLine } = require('../../common/contract-builder')
2 |
3 | module.exports = [
4 | 'if (a > b) {}',
5 | 'if (a > b) {} else {}',
6 | 'while (a > b) {}',
7 | 'do {} while (a > b);',
8 | 'for (;;) {}',
9 | 'for (uint i = 0;;) {}',
10 | 'for (; a < b;) {}',
11 | 'for (;; i += 1) {}',
12 | 'for (uint i = 0;; i += 1) {}',
13 | 'for (uint i = 0; i += 1;) {}',
14 | 'for (; a < b; i += 1) {}',
15 | 'for (uint i = 0; a < b; i += 1) {}',
16 | multiLine('if (a < b) { ', ' test1(); ', '} else { ', ' test2(); ', '} '),
17 | multiLine('do { ', ' test1(); ', '} while (a < b); '),
18 | ]
19 |
--------------------------------------------------------------------------------
/test/fixtures/align/statements_with_incorrect_indents.js:
--------------------------------------------------------------------------------
1 | const { multiLine } = require('../../common/contract-builder')
2 |
3 | module.exports = [
4 | 'if(a > b) {}',
5 | 'if (a > b ) {} else {}',
6 | 'while ( a > b) {}',
7 | 'do {} while (a > b );',
8 | 'for (;; ) {}',
9 | 'for (uint i = 0;; ) {}',
10 | 'for (;a < b; ) {}',
11 | 'for (;;i += 1) {}',
12 | 'for (uint i = 0;;i += 1) {}',
13 | 'for (uint i = 0;i += 1;) {}',
14 | 'for (;a < b; i += 1) {}',
15 | 'for (uint i = 0;a < b; i += 1) {}',
16 | multiLine(
17 | 'if (a < b) { ',
18 | ' test1(); ',
19 | '} ',
20 | 'else { ',
21 | ' test2(); ',
22 | '} '
23 | ),
24 | multiLine('do { ', ' test1(); ', '} ', 'while (a < b); '),
25 | ]
26 |
--------------------------------------------------------------------------------
/test/fixtures/best-practices/--fallback-not-payable.js:
--------------------------------------------------------------------------------
1 | const { contractWith } = require('../../common/contract-builder')
2 |
3 | module.exports = contractWith('function () public {}')
4 |
--------------------------------------------------------------------------------
/test/fixtures/best-practices/--fallback-payable.js:
--------------------------------------------------------------------------------
1 | const { contractWith } = require('../../common/contract-builder')
2 |
3 | module.exports = contractWith('function () public payable {}')
4 |
--------------------------------------------------------------------------------
/test/fixtures/best-practices/code-complexity-high.js:
--------------------------------------------------------------------------------
1 | const { multiLine } = require('../../common/contract-builder')
2 |
3 | module.exports = multiLine(
4 | ' if (a > b) { ',
5 | ' if (b > c) { ',
6 | ' if (c > d) { ',
7 | ' if (d > e) { ',
8 | ' } else { ',
9 | ' } ',
10 | ' } ',
11 | ' } ',
12 | ' } ',
13 | 'for (i = 0; i < b; i += 1) { } ',
14 | 'do { d++; } while (b > c); ',
15 | 'while (d > e) { } '
16 | )
17 |
--------------------------------------------------------------------------------
/test/fixtures/best-practices/code-complexity-low.js:
--------------------------------------------------------------------------------
1 | const { multiLine } = require('../../common/contract-builder')
2 |
3 | module.exports = multiLine(
4 | ' if (a > b) { ',
5 | ' if (b > c) { ',
6 | ' if (c > d) { ',
7 | ' } ',
8 | ' } ',
9 | ' } ',
10 | 'for (i = 0; i < b; i += 1) { } ',
11 | 'do { d++; } while (b > c); ',
12 | 'while (d > e) { } '
13 | )
14 |
--------------------------------------------------------------------------------
/test/fixtures/best-practices/number-of-states-high.js:
--------------------------------------------------------------------------------
1 | const { contractWith, stateDef } = require('../../common/contract-builder')
2 |
3 | module.exports = contractWith(stateDef(16))
4 |
--------------------------------------------------------------------------------
/test/fixtures/best-practices/number-of-states-low.js:
--------------------------------------------------------------------------------
1 | const { contractWith, stateDef, constantDef } = require('../../common/contract-builder')
2 |
3 | module.exports = contractWith([stateDef(10), constantDef(10)].join('\n'))
4 |
--------------------------------------------------------------------------------
/test/fixtures/best-practices/one-contract-per-file.js:
--------------------------------------------------------------------------------
1 | const ONE_CONTRACT = `
2 | pragma solidity 0.8.0;
3 |
4 | contract A {
5 | uint256 public constant TESTA = "testA";
6 | }
7 | `
8 |
9 | const TWO_CONTRACTS = `
10 | pragma solidity 0.8.0;
11 |
12 | contract A {
13 | uint256 public constant TESTA = "testA";
14 | }
15 |
16 | contract B {
17 | uint256 public constant TESTB = "testB";
18 | }
19 | `
20 |
21 | const THREE_CONTRACTS = `
22 | pragma solidity 0.8.0;
23 |
24 | contract A {
25 | uint256 public constant TESTA = "testA";
26 | }
27 |
28 | contract B {
29 | uint256 public constant TESTB = "testB";
30 | }
31 |
32 | contract C {
33 | uint256 public constant TESTC = "testC";
34 | }
35 | `
36 |
37 | const TWO_LIBRARIES = `
38 | pragma solidity 0.8.0;
39 |
40 | library A { }
41 |
42 | library B { }
43 | `
44 |
45 | const ONE_CONTRACT_WITH_INTERFACES = `
46 | pragma solidity 0.8.0;
47 |
48 | contract A { }
49 |
50 | interface B { }
51 |
52 | interface C { }
53 | `
54 |
55 | const ONE_LIBRARY_WITH_INTERFACES = `
56 | pragma solidity 0.8.0;
57 |
58 | library A { }
59 |
60 | interface B { }
61 |
62 | interface C { }
63 | `
64 |
65 | module.exports = {
66 | ONE_CONTRACT,
67 | TWO_CONTRACTS,
68 | THREE_CONTRACTS,
69 | TWO_LIBRARIES,
70 | ONE_CONTRACT_WITH_INTERFACES,
71 | ONE_LIBRARY_WITH_INTERFACES,
72 | }
73 |
--------------------------------------------------------------------------------
/test/fixtures/best-practices/require-with-reason.js:
--------------------------------------------------------------------------------
1 | const { funcWith } = require('../../common/contract-builder')
2 |
3 | module.exports = funcWith(`require(!has(role, account), "Roles: account already has role");
4 | role.bearer[account] = true;
5 | role.bearer[account] = true;`)
6 |
--------------------------------------------------------------------------------
/test/fixtures/best-practices/require-without-reason.js:
--------------------------------------------------------------------------------
1 | const { funcWith } = require('../../common/contract-builder')
2 |
3 | module.exports = funcWith(`require(!has(role, account));
4 | role.bearer[account] = true;
5 | role.bearer[account] = true;`)
6 |
--------------------------------------------------------------------------------
/test/fixtures/miscellaneous/public-function-no-override.js:
--------------------------------------------------------------------------------
1 | module.exports = `pragma solidity ^0.7.0;
2 |
3 | contract Foo {
4 | function foo() public {}
5 | }
6 | `
7 |
--------------------------------------------------------------------------------
/test/fixtures/miscellaneous/public-function-with-override.js:
--------------------------------------------------------------------------------
1 | module.exports = `pragma solidity ^0.7.0;
2 |
3 | contract Foo is FooInterface {
4 | function foo() public override {}
5 | }
6 | `
7 |
--------------------------------------------------------------------------------
/test/fixtures/miscellaneous/string-with-double-quotes.js:
--------------------------------------------------------------------------------
1 | const { contractWith } = require('../../common/contract-builder')
2 |
3 | module.exports = contractWith('string private a = "test";')
4 |
--------------------------------------------------------------------------------
/test/fixtures/miscellaneous/string-with-single-quotes.js:
--------------------------------------------------------------------------------
1 | const { contractWith } = require('../../common/contract-builder')
2 |
3 | module.exports = contractWith("string private a = 'test';")
4 |
--------------------------------------------------------------------------------
/test/fixtures/naming/func-named-parameters.js:
--------------------------------------------------------------------------------
1 | const FUNCTION_CALLS_ERRORS = {
2 | err1: {
3 | code: 'funcName(_sender, amount, receiver, token1, token2, token3);',
4 | minUnnamed: 5,
5 | },
6 |
7 | err2: {
8 | code: 'funcName(_sender, amount, receiver, token1, token2);',
9 | minUnnamed: 4,
10 | },
11 |
12 | err3: {
13 | code: 'funcName(_sender, amount, receiver, token1, token2);',
14 | minUnnamed: 0,
15 | },
16 | }
17 |
18 | const FUNCTION_CALLS_OK = {
19 | ok1: {
20 | code: 'funcName();',
21 | minUnnamed: 0,
22 | },
23 |
24 | ok2: {
25 | code: 'address(0);',
26 | minUnnamed: 10,
27 | },
28 |
29 | ok3: {
30 | code: 'funcName({ sender: _sender, amount: _amount, receiver: _receiver });',
31 | minUnnamed: 1,
32 | },
33 |
34 | ok4: {
35 | code: 'assert(1 == 3);',
36 | minUnnamed: 1,
37 | },
38 |
39 | ok5: {
40 | code: 'bytes foo = abi.encodeWithSelector(hex"0102030405060708", uint16(0xff00));',
41 | minUnnamed: 2,
42 | },
43 |
44 | ok6: {
45 | code: 'funcName({ sender: _sender, amount: _amount, receiver: _receiver, token1: _token1, token2: _token2 });',
46 | minUnnamed: 5,
47 | },
48 |
49 | ok7: {
50 | code: 'new BeaconProxy(address(0),abi.encodeWithSelector(bytes4(""),address(0),address(0),address(0)));',
51 | minUnnamed: 2,
52 | },
53 |
54 | ok8: {
55 | code: 'salt = keccak256(abi.encode(msg.sender, block.chainid, salt));',
56 | minUnnamed: 0,
57 | },
58 |
59 | ok9: {
60 | code: 'require(foobar != address(0), "foobar must a valid address");',
61 | minUnnamed: 0,
62 | },
63 | }
64 |
65 | module.exports = { FUNCTION_CALLS_ERRORS, FUNCTION_CALLS_OK }
66 |
--------------------------------------------------------------------------------
/test/fixtures/order/visibility-modifier-first.js:
--------------------------------------------------------------------------------
1 | const { contractWith } = require('../../common/contract-builder')
2 |
3 | module.exports = contractWith('function a() public ownable() payable {}')
4 |
--------------------------------------------------------------------------------
/test/fixtures/order/visibility-modifier-not-first.js:
--------------------------------------------------------------------------------
1 | const { contractWith } = require('../../common/contract-builder')
2 |
3 | module.exports = contractWith('function a() ownable() public payable {}')
4 |
--------------------------------------------------------------------------------
/test/fixtures/security/contracts-with-free-functions.js:
--------------------------------------------------------------------------------
1 | const CONTRACTS_FREE_FUNCTIONS_ERRORS_2 = `
2 | function freeAa() returns(bool) {
3 | return true;
4 | }
5 | contract A {
6 | // error here
7 | function functionPublicViewA() returns (uint256) {
8 | return 1;
9 | }
10 | }
11 |
12 | function freeBb() returns(bool) {
13 | return true;
14 | }
15 | contract B {
16 | // error here
17 | function functionPublicViewA() returns (uint256) {
18 | return 1;
19 | }
20 |
21 | function functionPublicPureB() internal pure returns (bool) {
22 | return true;
23 | }
24 | }
25 | `
26 |
27 | const CONTRACT_FREE_FUNCTIONS_ERRORS_1 = `
28 | contract A {
29 | constructor() {}
30 |
31 | // error here
32 | function functionPublicViewA() returns (uint256) {
33 | return 1;
34 | }
35 | }
36 |
37 | function freeBb() returns(bool) {
38 | return true;
39 | }
40 | `
41 |
42 | const NOCONTRACT_FREE_FUNCTION_ERRORS_0 = `
43 | // NO error here
44 | function functionPublicViewA() returns (uint256) {
45 | return 1;
46 | }
47 | `
48 |
49 | const CONTRACT_FREE_FUNCTIONS_ERRORS_0 = `
50 | function freeBb() returns(bool) {
51 | return true;
52 | }
53 |
54 | contract A {
55 | constructor() {}
56 |
57 | // NO error here
58 | function functionPublicViewA() external returns (uint256) {
59 | return 1;
60 | }
61 | }
62 | `
63 |
64 | module.exports = {
65 | CONTRACTS_FREE_FUNCTIONS_ERRORS_2,
66 | CONTRACT_FREE_FUNCTIONS_ERRORS_1,
67 | NOCONTRACT_FREE_FUNCTION_ERRORS_0,
68 | CONTRACT_FREE_FUNCTIONS_ERRORS_0,
69 | }
70 |
--------------------------------------------------------------------------------
/test/fixtures/security/functions-with-visibility.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | 'function b() internal { }',
3 | 'function b() external { }',
4 | 'function b() private { }',
5 | 'function b() public { }',
6 | 'constructor() public { }',
7 | ]
8 |
--------------------------------------------------------------------------------
/test/fixtures/security/functions-without-visibility.js:
--------------------------------------------------------------------------------
1 | module.exports = ['function b() { }']
2 |
--------------------------------------------------------------------------------
/test/fixtures/security/low-level-calls.js:
--------------------------------------------------------------------------------
1 | const WARN_LOW_LEVEL_CODES = [
2 | 'anyAddress.call(code);',
3 | 'a.callcode(test1);',
4 | 'a.delegatecall(test1);',
5 | 'anyAddress.call.value(code)();',
6 | ]
7 | const ALLOWED_LOW_LEVEL_CODES = ['anyAddress.call{value: 1 ether}("");']
8 |
9 | module.exports = [WARN_LOW_LEVEL_CODES, ALLOWED_LOW_LEVEL_CODES]
10 |
--------------------------------------------------------------------------------
/test/fixtures/security/reentrancy-invulnerable.js:
--------------------------------------------------------------------------------
1 | const { contractWith, funcWith } = require('../../common/contract-builder')
2 |
3 | module.exports = [
4 | contractWith(`
5 | mapping(address => uint) private shares;
6 |
7 | function b() external {
8 | uint amount = shares[msg.sender];
9 | shares[msg.sender] = 0;
10 | msg.sender.transfer(amount);
11 | }
12 | `),
13 | contractWith(`
14 | mapping(address => uint) private shares;
15 |
16 | function b() external {
17 | uint amount = shares[msg.sender];
18 | user.test(amount);
19 | shares[msg.sender] = 0;
20 | }
21 | `),
22 | funcWith(`
23 | uint[] shares;
24 | uint amount = shares[msg.sender];
25 | msg.sender.transfer(amount);
26 | shares[msg.sender] = 0;
27 | `),
28 | ]
29 |
--------------------------------------------------------------------------------
/test/fixtures/security/reentrancy-vulnerable.js:
--------------------------------------------------------------------------------
1 | const { contractWith } = require('../../common/contract-builder')
2 |
3 | module.exports = [
4 | contractWith(`
5 | mapping(address => uint) private shares;
6 |
7 | function b() external {
8 | uint amount = shares[msg.sender];
9 | bool a = msg.sender.send(amount);
10 | if (a) { shares[msg.sender] = 0; }
11 | }
12 | `),
13 | contractWith(`
14 | mapping(address => uint) private shares;
15 |
16 | function b() external {
17 | uint amount = shares[msg.sender];
18 | msg.sender.transfer(amount);
19 | shares[msg.sender] = 0;
20 | }
21 | `),
22 | ]
23 |
--------------------------------------------------------------------------------
/test/helpers/solhint_config_test.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["solhint:recommended"]
3 | }
--------------------------------------------------------------------------------
/test/parse-error.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const { assertErrorCount } = require('./common/asserts')
3 | const linter = require('../lib/index')
4 |
5 | describe('Parse error', () => {
6 | it('should report parse errors', () => {
7 | const report = linter.processStr('contract Foo {', {})
8 |
9 | assertErrorCount(report, 1)
10 | const error = report.reports[0]
11 | assert.equal(error.line, 1)
12 | assert.equal(error.column, 14)
13 | assert.ok(error.message.startsWith("Parse error: mismatched input ''"))
14 | })
15 |
16 | it('should report multiple parse errors', () => {
17 | const report = linter.processStr(
18 | `
19 | contract Foo {}}
20 | contract Bar {
21 | `,
22 | {}
23 | )
24 |
25 | assertErrorCount(report, 2)
26 | const messages = report.reports.map((error) => error.message)
27 | assert.ok(messages[0].startsWith("Parse error: extraneous input '}' expecting"))
28 | assert.ok(messages[1].startsWith("Parse error: mismatched input '' expecting"))
29 | })
30 | })
31 |
32 | describe('New Parsers support', () => {
33 | it('0.19.0 parser should support transient variable', () => {
34 | const report = linter.processStr('contract Foo { uint256 transient counter; }', {})
35 |
36 | assertErrorCount(report, 0)
37 | })
38 | })
39 |
--------------------------------------------------------------------------------
/test/rules/best-practices/function-max-lines.js:
--------------------------------------------------------------------------------
1 | const _ = require('lodash')
2 | const { assertErrorCount, assertNoErrors, assertErrorMessage } = require('../../common/asserts')
3 | const linter = require('../../../lib/index')
4 | const { funcWith } = require('../../common/contract-builder')
5 |
6 | describe('Linter - function-max-lines', () => {
7 | it('should raise error for function with 51 lines', () => {
8 | const code = funcWith(emptyLines(51))
9 |
10 | const report = linter.processStr(code, {
11 | rules: { 'function-max-lines': 'error' },
12 | })
13 |
14 | assertErrorCount(report, 1)
15 | assertErrorMessage(report, 'no more than')
16 | })
17 |
18 | it('should not raise error for function with 50 lines', () => {
19 | const code = funcWith(emptyLines(50))
20 |
21 | const report = linter.processStr(code, {
22 | rules: { 'function-max-lines': 'error' },
23 | })
24 |
25 | assertNoErrors(report)
26 | })
27 |
28 | it('should not raise error for function with 99 lines with 100 allowed', () => {
29 | const code = funcWith(emptyLines(99))
30 |
31 | const report = linter.processStr(code, {
32 | rules: { 'function-max-lines': ['error', 100] },
33 | })
34 |
35 | assertNoErrors(report)
36 | })
37 |
38 | function repeatLines(line, count) {
39 | return _.times(count)
40 | .map(() => line)
41 | .join('\n')
42 | }
43 |
44 | function emptyLines(count) {
45 | return repeatLines('', count)
46 | }
47 | })
48 |
--------------------------------------------------------------------------------
/test/rules/best-practices/interface-starts-with-i.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const { processStr } = require('../../../lib/index')
3 |
4 | const config = {
5 | rules: { 'interface-starts-with-i': 'error' },
6 | }
7 |
8 | describe('Linter - interface-starts-with-i', () => {
9 | it('should raise error for interface not starting with I', () => {
10 | const code = 'interface Foo {}'
11 | const report = processStr(code, config)
12 |
13 | assert.equal(report.errorCount, 1)
14 | assert.ok(report.messages[0].message === `Interface name 'Foo' must start with "I"`)
15 | })
16 |
17 | it('should not raise error for interface starting with I', () => {
18 | const code = 'interface IFoo {}'
19 |
20 | const report = processStr(code, config)
21 | assert.equal(report.errorCount, 0)
22 | })
23 | })
24 |
--------------------------------------------------------------------------------
/test/rules/miscellaneous/comprehensive-interface.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const linter = require('../../../lib/index')
3 |
4 | describe('Linter - comprehensive-interface', () => {
5 | it('should raise an error', () => {
6 | const code = require('../../fixtures/miscellaneous/public-function-no-override')
7 |
8 | const report = linter.processStr(code, {
9 | rules: { 'comprehensive-interface': 'error' },
10 | })
11 |
12 | assert.equal(report.errorCount, 1)
13 | assert.ok(
14 | report.messages[0].message.includes(
15 | 'All public or external methods in a contract must override a definition from an interface'
16 | )
17 | )
18 | })
19 |
20 | it('should not raise an error', () => {
21 | const code = require('../../fixtures/miscellaneous/public-function-with-override')
22 |
23 | const report = linter.processStr(code, {
24 | rules: { 'comprehensive-interface': 'error' },
25 | })
26 |
27 | assert.equal(report.errorCount, 0)
28 | })
29 | })
30 |
--------------------------------------------------------------------------------
/test/rules/miscellaneous/duplicated-imports.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const linter = require('../../../lib/index')
3 | const { assertNoErrors, assertErrorCount } = require('../../common/asserts')
4 | const TEST_CASES = require('../../fixtures/miscellaneous/duplicated-imports-data')
5 |
6 | describe('Linter - duplicated-imports', () => {
7 | for (const importCase of TEST_CASES.duplicates) {
8 | it(`Should report ${importCase.qtyDuplicates} error/s for ${importCase.name}`, () => {
9 | const code = importCase.code
10 |
11 | const report = linter.processStr(code, {
12 | rules: { 'duplicated-imports': 'error' },
13 | })
14 |
15 | // assert.equal(report.errorCount, )
16 | assertErrorCount(report, importCase.qtyDuplicates)
17 |
18 | for (let i = 0; i < report.reports.length; i++) {
19 | assert.ok(report.reports[i].message.includes(importCase.message[i]))
20 | }
21 | })
22 | }
23 |
24 | for (const importCase of TEST_CASES.noDuplicates) {
25 | it(`Should NOT report errors for ${importCase.name}`, () => {
26 | const code = importCase.code
27 |
28 | const report = linter.processStr(code, {
29 | rules: { 'duplicated-imports': 'error' },
30 | })
31 |
32 | assertNoErrors(report)
33 | })
34 | }
35 | })
36 |
--------------------------------------------------------------------------------
/test/rules/naming/event-name-capwords.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const linter = require('../../../lib/index')
3 | const contractWith = require('../../common/contract-builder').contractWith
4 |
5 | describe('Linter - event-name-capwords', () => {
6 | it('should raise event name error for event in mixedCase', () => {
7 | const code = contractWith('event EventCap(uint a);')
8 |
9 | const report = linter.processStr(code, {
10 | rules: { 'event-name-capwords': 'error' },
11 | })
12 |
13 | assert.equal(report.errorCount, 0)
14 | })
15 |
16 | it('should raise event name error for event in mixedCase', () => {
17 | const code = contractWith('event event1(uint a);')
18 |
19 | const report = linter.processStr(code, {
20 | rules: { 'event-name-capwords': 'error' },
21 | })
22 |
23 | assert.equal(report.errorCount, 1)
24 | assert.ok(report.messages[0].message.includes('CapWords'))
25 | })
26 |
27 | describe('Event name with $ character', () => {
28 | const WITH_$ = {
29 | 'starting with $': contractWith('event $Event1(uint a);'),
30 | 'containing a $': contractWith('event Eve$nt1(uint a);'),
31 | 'ending with $': contractWith('event Event1$(uint a);'),
32 | 'only with $': contractWith('event $(uint a);'),
33 | }
34 |
35 | for (const [key, code] of Object.entries(WITH_$)) {
36 | it(`should not raise event name error for Events ${key}`, () => {
37 | const report = linter.processStr(code, {
38 | rules: { 'event-name-capwords': 'error' },
39 | })
40 |
41 | assert.equal(report.errorCount, 0)
42 | })
43 | }
44 | })
45 | })
46 |
--------------------------------------------------------------------------------
/test/rules/naming/func-name-mixedcase.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const linter = require('../../../lib/index')
3 | const contractWith = require('../../common/contract-builder').contractWith
4 |
5 | describe('Linter - func-name-mixedcase', () => {
6 | it('should raise incorrect func name error', () => {
7 | const code = contractWith('function AFuncName () public {}')
8 |
9 | const report = linter.processStr(code, {
10 | rules: { 'func-name-mixedcase': 'error' },
11 | })
12 |
13 | assert.equal(report.errorCount, 1)
14 | assert.ok(report.messages[0].message.includes('mixedCase'))
15 | })
16 |
17 | it('should dot raise incorrect func name error', () => {
18 | const code = contractWith('function aFunc1Nam23e () public {}')
19 |
20 | const report = linter.processStr(code, {
21 | rules: { 'func-name-mixedcase': 'error' },
22 | })
23 |
24 | assert.equal(report.errorCount, 0)
25 | })
26 |
27 | describe('Function names with $ character', () => {
28 | const WITH_$ = {
29 | 'starting with $': contractWith('function $aFunc1Nam23e () public {}'),
30 | 'containing a $': contractWith('function aFunc$1Nam23e () public {}'),
31 | 'ending with $': contractWith('function aFunc1Nam23e$ () public {}'),
32 | 'only with $': contractWith('function $() public {}'),
33 | }
34 |
35 | for (const [key, code] of Object.entries(WITH_$)) {
36 | it(`should not raise func name error for Functions ${key}`, () => {
37 | const report = linter.processStr(code, {
38 | rules: { 'func-name-mixedcase': 'error' },
39 | })
40 |
41 | assert.equal(report.errorCount, 0)
42 | })
43 | }
44 | })
45 | })
46 |
--------------------------------------------------------------------------------
/test/rules/naming/modifier-name-mixedcase.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const linter = require('../../../lib/index')
3 | const contractWith = require('../../common/contract-builder').contractWith
4 |
5 | describe('Linter - modifier-name-mixedcase', () => {
6 | it('should raise modifier name error', () => {
7 | const code = contractWith('modifier owned_by(address a) { }')
8 |
9 | const report = linter.processStr(code, {
10 | rules: { 'modifier-name-mixedcase': 'error' },
11 | })
12 |
13 | assert.equal(report.errorCount, 1)
14 | assert.ok(report.messages[0].message.includes('mixedCase'))
15 | })
16 |
17 | it('should not raise modifier name error', () => {
18 | const code = contractWith('modifier ownedBy(address a) { }')
19 |
20 | const report = linter.processStr(code, {
21 | rules: { 'modifier-name-mixedcase': 'error' },
22 | })
23 |
24 | assert.equal(report.errorCount, 0)
25 | })
26 |
27 | describe('with $ character', () => {
28 | const WITH_$ = {
29 | 'starting with $': contractWith('modifier $ownedBy(address a) { }'),
30 | 'containing a $': contractWith('modifier owned$By(address a) { }'),
31 | 'ending with $': contractWith('modifier ownedBy$(address a) { }'),
32 | 'only with $': contractWith('modifier $(uint a) { }'),
33 | }
34 |
35 | for (const [key, code] of Object.entries(WITH_$)) {
36 | it(`should not raise func name error for Modifiers ${key}`, () => {
37 | const report = linter.processStr(code, {
38 | rules: { 'modifier-name-mixedcase': 'error' },
39 | })
40 |
41 | assert.equal(report.errorCount, 0)
42 | })
43 | }
44 | })
45 | })
46 |
--------------------------------------------------------------------------------
/test/rules/naming/use-forbidden-name.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const linter = require('../../../lib/index')
3 | const funcWith = require('../../common/contract-builder').funcWith
4 |
5 | describe('Linter - use-forbidden-name', () => {
6 | it('should raise forbidden name error', () => {
7 | const code = funcWith('uint l = 0;')
8 |
9 | const report = linter.processStr(code, {
10 | rules: { 'no-unused-vars': 'error', 'use-forbidden-name': 'error' },
11 | })
12 |
13 | assert.equal(report.errorCount, 2)
14 | assert.ok(report.messages[0].message.includes('Avoid to use'))
15 | })
16 | })
17 |
--------------------------------------------------------------------------------
/test/rules/order/imports-on-top.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const linter = require('../../../lib/index')
3 |
4 | describe('Linter - imports-on-top', () => {
5 | it('should raise import not on top error', () => {
6 | const code = `
7 | contract A {}
8 |
9 |
10 | import "lib.sol";
11 | `
12 |
13 | const report = linter.processStr(code, {
14 | rules: { 'imports-on-top': 'error' },
15 | })
16 |
17 | assert.equal(report.errorCount, 1)
18 | assert.ok(report.messages[0].message.includes('Import'))
19 | })
20 |
21 | it('should not raise import not on top error', () => {
22 | const code = `
23 | pragma solidity 0.4.17;
24 | import "lib.sol";
25 |
26 |
27 | contract A {}
28 | `
29 |
30 | const report = linter.processStr(code, {
31 | rules: { 'imports-on-top': 'error' },
32 | })
33 |
34 | assert.equal(report.errorCount, 0)
35 | })
36 | })
37 |
--------------------------------------------------------------------------------
/test/rules/order/visibility-modifier-order.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const linter = require('../../../lib/index')
3 | const { contractWith } = require('../../common/contract-builder')
4 |
5 | describe('Linter - visibility-modifier-order', () => {
6 | it('should raise visibility modifier error', () => {
7 | const code = require('../../fixtures/order/visibility-modifier-not-first')
8 |
9 | const report = linter.processStr(code, {
10 | rules: { 'visibility-modifier-order': 'error' },
11 | })
12 |
13 | assert.equal(report.errorCount, 1)
14 | })
15 |
16 | it('should not raise visibility modifier error', () => {
17 | const code = require('../../fixtures/order/visibility-modifier-first')
18 |
19 | const report = linter.processStr(code, {
20 | rules: { 'visibility-modifier-order': 'error' },
21 | })
22 |
23 | assert.equal(report.errorCount, 0)
24 | })
25 |
26 | it('should not raise error if a payable address is a parameter', () => {
27 | const code = contractWith('function foo(address payable addr) public payable {}')
28 |
29 | const report = linter.processStr(code, {
30 | rules: { 'visibility-modifier-order': 'error' },
31 | })
32 |
33 | assert.equal(report.errorCount, 0)
34 | })
35 | })
36 |
--------------------------------------------------------------------------------
/test/rules/security/avoid-call-value.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const linter = require('../../../lib/index')
3 | const funcWith = require('../../common/contract-builder').funcWith
4 |
5 | describe('Linter - avoid-call-value', () => {
6 | it('should return "call.value" verification error', () => {
7 | const code = funcWith('x.call.value(55)();')
8 |
9 | const report = linter.processStr(code, {
10 | rules: { 'avoid-call-value': 'error' },
11 | })
12 |
13 | assert.equal(report.errorCount, 1)
14 | assert.ok(report.reports[0].message.includes('call.value'))
15 | })
16 | })
17 |
--------------------------------------------------------------------------------
/test/rules/security/avoid-low-level-calls.js:
--------------------------------------------------------------------------------
1 | const linter = require('../../../lib/index')
2 | const funcWith = require('../../common/contract-builder').funcWith
3 | const { assertWarnsCount, assertErrorMessage } = require('../../common/asserts')
4 |
5 | describe('Linter - avoid-low-level-calls', () => {
6 | const LOW_LEVEL_CALLS = require('../../fixtures/security/low-level-calls')
7 | const WARN_LOW_LEVEL_CALLS = LOW_LEVEL_CALLS[0].map(funcWith)
8 | const ALLOWED_LOW_LEVEL_CALLS = LOW_LEVEL_CALLS[1].map(funcWith)
9 |
10 | WARN_LOW_LEVEL_CALLS.forEach((curCode) =>
11 | it('should return warn when code contains low level calls', () => {
12 | const report = linter.processStr(curCode, {
13 | rules: { 'avoid-low-level-calls': 'warn' },
14 | })
15 |
16 | assertWarnsCount(report, 1)
17 | assertErrorMessage(report, 'low level')
18 | })
19 | )
20 |
21 | ALLOWED_LOW_LEVEL_CALLS.forEach((curCode) =>
22 | it('should not return warn when code contains allowed low level calls', () => {
23 | const report = linter.processStr(curCode, {
24 | rules: { 'avoid-low-level-calls': 'warn' },
25 | })
26 |
27 | assertWarnsCount(report, 0)
28 | })
29 | )
30 | })
31 |
--------------------------------------------------------------------------------
/test/rules/security/avoid-sha3.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const linter = require('../../../lib/index')
3 | const funcWith = require('../../common/contract-builder').funcWith
4 |
5 | describe('Linter - avoid-sha3', () => {
6 | const DEPRECATION_ERRORS = ['sha3("test");']
7 |
8 | DEPRECATION_ERRORS.forEach((curText) =>
9 | it(`should return error that used deprecations ${curText}`, () => {
10 | const code = funcWith(curText)
11 |
12 | const report = linter.processStr(code, {
13 | rules: { 'avoid-sha3': 'error' },
14 | })
15 |
16 | assert.equal(report.errorCount, 1)
17 | assert.ok(report.reports[0].message.includes('deprecate'))
18 | })
19 | )
20 |
21 | const ALMOST_DEPRECATION_ERRORS = ['sha33("test");']
22 |
23 | ALMOST_DEPRECATION_ERRORS.forEach((curText) =>
24 | it(`should not return error when doing ${curText}`, () => {
25 | const code = funcWith(curText)
26 |
27 | const report = linter.processStr(code, {
28 | rules: { 'avoid-sha3': 'error' },
29 | })
30 |
31 | assert.equal(report.errorCount, 0)
32 | })
33 | )
34 | })
35 |
--------------------------------------------------------------------------------
/test/rules/security/avoid-suicide.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const linter = require('../../../lib/index')
3 | const funcWith = require('../../common/contract-builder').funcWith
4 | const contractWith = require('../../common/contract-builder').contractWith
5 |
6 | describe('Linter - avoid-suicide', () => {
7 | const DEPRECATION_ERRORS = ['suicide();']
8 |
9 | DEPRECATION_ERRORS.forEach((curText) =>
10 | it(`should return error that used deprecations ${curText}`, () => {
11 | const code = funcWith(curText)
12 |
13 | const report = linter.processStr(code, {
14 | rules: { 'avoid-suicide': 'error' },
15 | })
16 |
17 | assert.equal(report.errorCount, 1)
18 | assert.ok(report.reports[0].message.includes('deprecate'))
19 | })
20 | )
21 |
22 | const ALMOST_DEPRECATION_ERRORS = ['suicides();', 'selfdestruct();']
23 |
24 | ALMOST_DEPRECATION_ERRORS.forEach((curText) =>
25 | it(`should not return error when doing ${curText}`, () => {
26 | const code = funcWith(curText)
27 |
28 | const report = linter.processStr(code, {
29 | rules: { 'avoid-suicide': 'error' },
30 | })
31 |
32 | assert.equal(report.errorCount, 0)
33 | })
34 | )
35 |
36 | it(`should not return error when doing for struct name suicide`, () => {
37 | const code = contractWith('struct AnotherNiceStruct { uint256 suicide; uint256 c; }')
38 |
39 | const report = linter.processStr(code, {
40 | rules: { 'avoid-suicide': 'error' },
41 | })
42 |
43 | assert.equal(report.errorCount, 0)
44 | })
45 | })
46 |
--------------------------------------------------------------------------------
/test/rules/security/avoid-throw.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const linter = require('../../../lib/index')
3 | const funcWith = require('../../common/contract-builder').funcWith
4 |
5 | describe('Linter - avoid-throw', () => {
6 | const DEPRECATION_ERRORS = ['throw;']
7 |
8 | DEPRECATION_ERRORS.forEach((curText) =>
9 | it(`should return error that used deprecations ${curText}`, () => {
10 | const code = funcWith(curText)
11 |
12 | const report = linter.processStr(code, {
13 | rules: { 'avoid-throw': 'error' },
14 | })
15 |
16 | assert.equal(report.errorCount, 1)
17 | assert.ok(report.reports[0].message.includes('deprecate'))
18 | })
19 | )
20 |
21 | const ALMOST_DEPRECATION_ERRORS = ['throwing;']
22 |
23 | ALMOST_DEPRECATION_ERRORS.forEach((curText) =>
24 | it(`should not return error when doing ${curText}`, () => {
25 | const code = funcWith(curText)
26 |
27 | const report = linter.processStr(code, {
28 | rules: { 'avoid-throw': 'error' },
29 | })
30 |
31 | assert.equal(report.errorCount, 0)
32 | })
33 | )
34 | })
35 |
--------------------------------------------------------------------------------
/test/rules/security/avoid-tx-origin.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const linter = require('../../../lib/index')
3 | const funcWith = require('../../common/contract-builder').funcWith
4 | const { assertErrorMessage } = require('../../common/asserts')
5 |
6 | describe('Linter - avoid-tx-origin', () => {
7 | it('should return error that used tx.origin', () => {
8 | const code = funcWith(`
9 | uint aRes = tx.origin;
10 | `)
11 |
12 | const report = linter.processStr(code, {
13 | rules: { 'avoid-tx-origin': 'error' },
14 | })
15 |
16 | assert.equal(report.errorCount, 1)
17 | assertErrorMessage(report, 'origin')
18 | })
19 | })
20 |
--------------------------------------------------------------------------------
/test/rules/security/multiple-sends.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const linter = require('../../../lib/index')
3 | const funcWith = require('../../common/contract-builder').funcWith
4 | const { assertErrorMessage, assertErrorCount } = require('../../common/asserts')
5 |
6 | describe('Linter - multiple-sends', () => {
7 | it('should return the error that multiple send calls are being used in the same transaction', () => {
8 | const code = funcWith(`
9 | uint aRes = a.send(1);
10 | uint bRes = b.send(2);
11 | `)
12 |
13 | const report = linter.processStr(code, {
14 | rules: { 'multiple-sends': 'error' },
15 | })
16 |
17 | assert.equal(report.errorCount, 1)
18 | assert.ok(report.reports[0].message.includes('multiple'))
19 | })
20 |
21 | it('should return the error that multiple send calls are being used inside a loop', () => {
22 | const code = funcWith(`
23 | while (ac > b) { uint res = a.send(1); }
24 | `)
25 |
26 | const report = linter.processStr(code, {
27 | rules: { 'multiple-sends': 'error' },
28 | })
29 |
30 | assertErrorCount(report, 1)
31 | assertErrorMessage(report, 'multiple')
32 | })
33 | })
34 |
--------------------------------------------------------------------------------
/test/rules/security/no-complex-fallback.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const linter = require('../../../lib/index')
3 | const contractWith = require('../../common/contract-builder').contractWith
4 |
5 | describe('Linter - no-complex-fallback', () => {
6 | it('should return that fallback must be simple', () => {
7 | const code = contractWith(`function () public payable {
8 | make1();
9 | make2();
10 | }`)
11 |
12 | const report = linter.processStr(code, {
13 | rules: { 'no-complex-fallback': 'warn' },
14 | })
15 |
16 | assert.equal(report.warningCount, 1)
17 | assert.ok(report.reports[0].message.includes('Fallback'))
18 | })
19 | })
20 |
--------------------------------------------------------------------------------
/test/rules/security/no-inline-assembly.js:
--------------------------------------------------------------------------------
1 | const linter = require('../../../lib/index')
2 | const funcWith = require('../../common/contract-builder').funcWith
3 | const { assertWarnsCount, assertErrorMessage } = require('../../common/asserts')
4 |
5 | describe('Linter - no-inline-assembly', () => {
6 | it('should return warn when function use inline assembly', () => {
7 | const code = funcWith(' assembly { "test" } ')
8 |
9 | const report = linter.processStr(code, {
10 | rules: { 'no-inline-assembly': 'warn' },
11 | })
12 |
13 | assertWarnsCount(report, 1)
14 | assertErrorMessage(report, 'assembly')
15 | })
16 | })
17 |
--------------------------------------------------------------------------------
/test/rules/security/not-rely-on-block-hash.js:
--------------------------------------------------------------------------------
1 | const linter = require('../../../lib/index')
2 | const funcWith = require('../../common/contract-builder').funcWith
3 | const { assertWarnsCount, assertErrorMessage } = require('../../common/asserts')
4 |
5 | describe('Linter - not-rely-on-block-hash', () => {
6 | it('should return warn when function rely on block has', () => {
7 | const code = funcWith('end >= block.blockhash + daysAfter * 1 days;')
8 |
9 | const report = linter.processStr(code, {
10 | rules: { 'not-rely-on-block-hash': 'warn' },
11 | })
12 |
13 | assertWarnsCount(report, 1)
14 | assertErrorMessage(report, 'block.blockhash')
15 | })
16 | })
17 |
--------------------------------------------------------------------------------
/test/rules/security/not-rely-on-time.js:
--------------------------------------------------------------------------------
1 | const linter = require('../../../lib/index')
2 | const funcWith = require('../../common/contract-builder').funcWith
3 | const { assertWarnsCount, assertErrorMessage } = require('../../common/asserts')
4 |
5 | describe('Linter - not-rely-on-time', () => {
6 | const TIME_BASED_LOGIC = [
7 | funcWith('now >= start + daysAfter * 1 days;'),
8 | funcWith('start >= block.timestamp + daysAfter * 1 days;'),
9 | ]
10 |
11 | TIME_BASED_LOGIC.forEach((curCode) =>
12 | it('should return warn when business logic rely on time', () => {
13 | const report = linter.processStr(curCode, {
14 | rules: { 'not-rely-on-time': 'warn' },
15 | })
16 |
17 | assertWarnsCount(report, 1)
18 | assertErrorMessage(report, 'time')
19 | })
20 | )
21 | })
22 |
--------------------------------------------------------------------------------
/test/rules/security/reentrancy.js:
--------------------------------------------------------------------------------
1 | const linter = require('../../../lib/index')
2 | const { assertWarnsCount, assertErrorMessage, assertNoWarnings } = require('../../common/asserts')
3 |
4 | describe('Linter - reentrancy', () => {
5 | require('../../fixtures/security/reentrancy-vulnerable').forEach((curCode) =>
6 | it('should return warn when code contains possible reentrancy', () => {
7 | const report = linter.processStr(curCode, {
8 | rules: { reentrancy: 'warn' },
9 | })
10 |
11 | assertWarnsCount(report, 1)
12 | assertErrorMessage(report, 'reentrancy')
13 | })
14 | )
15 |
16 | require('../../fixtures/security/reentrancy-invulnerable').forEach((curCode) =>
17 | it('should not return warn when code do not contains transfer', () => {
18 | const report = linter.processStr(curCode, {
19 | rules: { reentrancy: 'warn' },
20 | })
21 |
22 | assertNoWarnings(report)
23 | })
24 | )
25 | })
26 |
--------------------------------------------------------------------------------
/test/rules/security/state-visibility.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const linter = require('../../../lib/index')
3 | const contractWith = require('../../common/contract-builder').contractWith
4 |
5 | describe('Linter - state-visibility', () => {
6 | it('should return required visibility error for state', () => {
7 | const code = contractWith('uint a;')
8 |
9 | const report = linter.processStr(code, {
10 | rules: { 'state-visibility': 'warn' },
11 | })
12 |
13 | assert.equal(report.warningCount, 1)
14 | assert.ok(report.reports[0].message.includes('visibility'))
15 | })
16 |
17 | const BLOCKS_WITH_DEFINITIONS = [
18 | contractWith('uint private a;'),
19 | contractWith('uint public a;'),
20 | contractWith('uint internal a;'),
21 | ]
22 |
23 | BLOCKS_WITH_DEFINITIONS.forEach((curData) =>
24 | it(`should not raise warn for blocks ${label(curData)}`, () => {
25 | const report = linter.processStr(curData, {
26 | rules: { 'state-visibility': 'warn' },
27 | })
28 |
29 | assert.equal(report.warningCount, 0)
30 | })
31 | )
32 |
33 | function label(data) {
34 | return data.split('\n')[0]
35 | }
36 | })
37 |
--------------------------------------------------------------------------------