solhint

repository·develop·Indexed 22 days ago

https://github.com/protofire/solhint

An open-source Solidity code linter (version 6.2.3) that provides security and style guide validations. It features a CLI for linting files and directories, automatic fixing for specific rules via the --fix flag, and support for ESLint-compatible formatters. Solhint can be configured using .solhint.json files, supports plugins and shared configurations, and can be deployed via npm or Docker.

Tokens
41.2K
Snippets
170
Records
223
Agent score
77%

What's inside solhint

  1. Use ESLint formatters with Solhint

    develop

    Solhint includes several ESLint-compatible formatters that can be used to control the output style of linting results. These formatters are pulled from the official ESLint repository and allow you to output results in various formats such as tables, JSON, or Unix-style text. To use a specific formatter, you typically pass the --format flag to the Solhint CLI followed by the name of the formatter file (e.g., stylish, json, or compact).

    solhint --format stylish path/to/contract.sol
  2. Use the not-rely-on-block-hash security rule

    develop

    The not-rely-on-block-hash rule prevents developers from relying on block.blockhash in Solidity smart contracts. This is a security best practice because miners can influence the value of the block hash, potentially leading to vulnerabilities.

    This rule is enabled by default if you use the "extends": "solhint:recommended" property in your Solhint configuration file.

    Severity Options: You can configure the severity of this rule using one of the following strings:

    • "error"
    • "warn" (Default)
    • "off"
    {
      "rules": {
        "not-rely-on-block-hash": "warn"
      }
    }
  3. Understand Solhint configuration inheritance

    develop

    Solhint uses hierarchical configuration. When linting a file, configurations are merged in a specific order to determine the final rules applied:

    1. extends resolution: Any entries in the extends array are resolved first.
    2. Directory hierarchy: Configurations are merged from the project root down to the file's location.

    Precedence Order (Lowest to Highest):

    1. Project root configuration
    2. Parent directory configurations
    3. The directory containing the file (highest precedence)

    Rule of thumb: extends are resolved first, then the directory hierarchy is applied. The configuration closest to the file being linted always wins and overrides rules from higher-level directories or extended configs.

  4. Use the avoid-tx-origin security rule

    develop

    The avoid-tx-origin rule is a security rule that flags the use of tx.origin in Solidity smart contracts. Using tx.origin for authorization is a known security risk as it can lead to phishing attacks.

    This rule is included by default when you use the "extends": "solhint:recommended" configuration. You can also configure its severity level manually.

  5. Understand the reentrancy rule

    develop

    The reentrancy rule is a security rule designed to prevent reentrancy vulnerabilities. It flags code patterns where state changes (such as updating a mapping or balance) happen after an external call or transfer (like msg.sender.transfer() or msg.sender.send()).

    To avoid this vulnerability, follow the Checks-Effects-Interactions pattern:

    1. Checks: Validate conditions (e.g., require statements).
    2. Effects: Update the contract's internal state (e.g., shares[msg.sender] = 0;).
    3. Interactions: Perform external calls or transfers (e.g., msg.sender.transfer(amount);).
    ### 👍 Correct Pattern (Checks-Effects-Interactions)
    
    ```solidity
    contract A {
        mapping(address => uint) private shares;
    
        function b() external {
            uint amount = shares[msg.sender];
            // Effect: Update state BEFORE the transfer
            shares[msg.sender] = 0;
            // Interaction: Perform the transfer
            msg.sender.transfer(amount);
        }
    }

    👎 Incorrect Pattern (Vulnerable)

    contract A {
        mapping(address => uint) private shares;
    
        function b() external {
            uint amount = shares[msg.sender];
            // Interaction: Perform the transfer
            msg.sender.transfer(amount);
            // Effect: State change happens AFTER the transfer (Vulnerable!)
            shares[msg.sender] = 0;
        }
    }
  6. Understand the imports-order hierarchy

    develop

    The imports-order rule organizes imports based on the following hierarchy:

    1. Special Paths & URLs: Paths starting with @ (e.g., @openzeppelin/) and full URLs (http:// or https://) are placed first.
    2. Direct vs. Relative: Direct imports are placed before relative imports.
    3. Directory Hierarchy: Relative paths are ordered by depth. For example, ./../../ comes before ./../, which comes before ./, which comes before ./foo.
    4. Alphabetical Order: For imports at the same level/path, they are ordered alphabetically (e.g., ./contract/Zbar.sol comes before ./interface/Ifoo.sol).

    Limitations & Behavior:

    • Unsupported Syntax: The rule does not support the import * as Alias from "./filename.sol" syntax.
    • Auto-fixing: When running Solhint with the --fix flag, the rule will rewrite relative paths to include the explicit current directory prefix. For example, ../folder/file.sol will be rewritten to ./../folder/file.sol.
  7. Use the avoid-call-value security rule

    develop

    The avoid-call-value rule is a security rule designed to prevent the use of the pattern .call.value()(). This pattern is often associated with dangerous or unintended execution flows in Solidity.

    This rule is included by default when you use the "extends": "solhint:recommended" property in your Solhint configuration file.

  8. Use the imports-on-top rule

    develop

    The imports-on-top rule ensures that all import statements are located at the top of the file. This rule is categorized under Style Guide Rules and is marked as Recommended.

    By default, this rule is enabled if you use the following configuration in your .solhint.json:

    {
      "extends": "solhint:recommended"
    }
    {
      "extends": "solhint:recommended"
    }