Skip to main content

Crate forge_lint

Crate forge_lint 

Source
Expand description

§Linter (lint)

Solidity linter for identifying potential errors, vulnerabilities, gas optimizations, and style guide violations. It helps enforce best practices and improve code quality within Foundry projects.

§Supported Lints

forge-lint includes rules across several categories:

  • High Severity:
    • incorrect-shift: Warns against shift operations where operands might be in the wrong order.
    • unchecked-call: Low-level calls should check the success return value.
    • erc20-unchecked-transfer: ERC20 transfer and transferFrom calls should check the return value.
    • rtlo: Flags Unicode bidirectional override characters (“Trojan Source”, CVE-2021-42574) that can hide malicious code.
    • reentrancy-unlimited-gas: Flags uncapped ETH-transferring low-level calls followed by writes to state that was read before the call.
  • Medium Severity:
    • boolean-cst: Flags misuse of boolean constants.
    • divide-before-multiply: Warns against performing division before multiplication in the same expression, which can cause precision loss.
    • incorrect-erc20-interface: Flags ERC20 interfaces and implementations with non-compliant function signatures.
    • incorrect-erc721-interface: Flags ERC721 interfaces and implementations with non-compliant function signatures.
    • incorrect-strict-equality: Dangerous strict equality check on an externally-influenced value (ETH balance, ERC-20 balance).
    • tx-origin: Flags use of tx.origin in authorization-like predicates.
    • uninitialized-local: Local variable is read before being explicitly initialized.
    • unsafe-typecast: Typecasts that can truncate values should be checked.
    • unused-return: Return value of an external call is not used.
    • weak-prng: Flags randomness-like expressions derived from predictable on-chain values.
  • Low Severity:
    • block-timestamp: Warns when block.timestamp is used in a comparison, as it may be manipulated by validators.
    • calls-loop: External calls inside loops can cause denial-of-service if a call reverts or exhausts gas.
    • delegatecall-loop: Payable functions should not use delegatecall inside a loop.
    • missing-zero-check: Address parameter is used in a state write or value transfer without a zero-address check.
    • return-bomb: External calls with a gas limit should not consume unbounded return data.
  • Informational / Style Guide:
    • boolean-equal: Boolean comparisons to constants should be simplified.
    • too-many-digits: Numeric literals with 5+ consecutive zeros are error-prone.
    • pascal-case-struct: Flags for struct names not adhering to PascalCase.
    • mixed-case-function: Flags for function names not adhering to mixedCase.
    • mixed-case-variable: Flags for mutable variable names not adhering to mixedCase.
    • screaming-snake-case-const: Flags for constant variable names not adhering to SCREAMING_SNAKE_CASE.
    • screaming-snake-case-immutable: Flags for immutable variable names not adhering to SCREAMING_SNAKE_CASE.
    • unused-import: Unused imports should be removed.
    • unaliased-plain-import: Use named imports {A, B} or alias import ".." as X.
    • named-struct-fields: Prefer initializing structs with named fields.
    • unsafe-cheatcode: Usage of unsafe cheatcodes that can perform dangerous operations.
    • multi-contract-file: Prefer having only one contract, interface, or library per file.
    • interface-file-naming: Interface file names should be prefixed with I.
    • interface-naming: Interface names should be prefixed with I.
    • pragma-inconsistent: Flags projects whose source files declare different Solidity pragma version requirements.
    • redundant-base-constructor-call: Flags explicit empty base-constructor arguments (e.g. is A()) when the base requires no arguments.
    • missing-inheritance: Flags contracts that implement every external function of an interface without explicitly inheriting from it.
    • low-level-calls: Direct use of low-level calls should be avoided.
    • event-fields: address and id-like (uint256/bytes32 named id/*Id) event parameters should be indexed for efficient log filtering.
  • Gas Optimizations:
    • asm-keccak256: Recommends using inline assembly for keccak256 for potential gas savings.
    • cache-array-length: Recommends caching dynamic array or bytes lengths used in for loop conditions.
    • costly-loop: Flags storage variable writes inside loops; accumulate into a local variable and write once after the loop instead.
    • could-be-immutable: Recommends declaring constructor-only state variables as immutable.
    • could-be-constant: Recommends declaring never-written state variables with a compile-time-constant initializer as constant.
    • custom-errors: Recommends using custom errors instead of strings and plain reverts for potential gas savings.
    • external-function: public functions never called internally should be declared external to avoid copying reference-type arguments into memory.
    • unused-state-variables: State variables that are never used should be removed.
    • var-read-using-this: Reads of state variables (or other view/pure functions) via this cause an unnecessary STATICCALL; access them directly.
  • Code Size:
    • unwrapped-modifier-logic: Recommends wrapping modifier logic to reduce contract code size.

§Configuration

The behavior of the SolidityLinter can be customized with the following options:

OptionDefaultDescription
with_severityNoneFilters active lints by their severity (High, Med, Low, Info, Gas, CodeSize). None means all severities.
with_lintsNoneSpecifies a list of SolLint instances to include. Overrides severity filter if a lint matches.
without_lintsNoneSpecifies a list of SolLint instances to exclude, even if they match other criteria.
with_descriptiontrueWhether to include the lint’s description in the diagnostic output.
with_json_emitterfalseIf true, diagnostics are output in rustc-compatible JSON format; otherwise, human-readable text.

§Contributing

Check out the foundry contribution guide.

Guidelines for contributing to forge lint:

§Opening an issue

  1. Create a short concise title describing an issue.
    • Bad Title Examples
      Forge lint does not work
      Forge lint breaks
      Forge lint unexpected behavior
    • Good Title Examples
      Forge lint does not flag incorrect shift operations
  2. Fill in the issue template fields that include foundry version, platform & component info.
  3. Provide the code snippets showing the current & expected behaviors.
  4. If it’s a feature request, specify why this feature is needed.
  5. Besides the default label (T-Bug for bugs or T-feature for features), add C-forge and Cmd-forge-fmt labels.

§Fixing A Bug

  1. Specify an issue that is being addressed in the PR description.
  2. Add a note on the solution in the PR description.
  3. Add a test case to lint/testdata that specifically demonstrates the bug and is fixed by your changes. Ensure all tests pass.

§Developing a New Lint Rule

Check the dev docs for a full implementation guide.

Modules§

linter
sol

Macros§

declare_forge_lint
Macro for defining lints and relevant metadata for the Solidity linter.
register_lints
Registers Solidity linter passes that can have both early and late variants.