Introducing Scopelint and a new Foundry Template

May 18, 2023 / Matt Solomon

Smart contract development is a sensitive task that demands secure, high-quality, and easy-to-read code. To help developers reach this goal, we have previously worked with other top engineers to come up with the Solidity and Foundry Best Practices. Now we're announcing two new tools to further help developers write safe, clean code: Scopelint, and a Foundry template.

Scopelint

Scopelint is a simple and opinionated tool designed for linting Solidity code and formatting Solidity and TOML files in Foundry projects. After installing it with `cargo install scopelint` (make sure you have the Rust toolchain installed), there are three commands you can run:

scopelint fmt

scopelint check

scopelint spec

scopelint fmt

This command is the simplest and most familiar. It will format:

  • Solidity files using the configuration specified in foundry.toml
  • TOML files using a hardcoded configuration that indents keys and sorts them alphabetically to improve readability.

scopelint check

This command ensures that development best practices are consistently followed by validating that:

  • Test names follow a convention of ^test(Fork)?(Fuzz)?(_Revert(If|When|On))?_(\w+)\*$. (To see a list of example valid test names, see here).
  • Constants and immutables are in ALL_CAPS.
  • Forge scripts only have one public method: run.
  • Internal or private functions in the src/ directory start with a leading underscore.
  • More checks are planned for the future. Scopelint is opinionated in that it does not currently let you configure these checks or turn any off. However, if there is demand for this it may be added in a future version. scopelint-check

scopelint spec

Most developers don't have formal specifications they are building towards, and instead only have a general idea of what they want their contracts to do. As a result, documentation and tests are the closest things many protocols have to a specification (unless they go through the formal verification process). And because documentation is often not written until the end of the development process, it is frequently incomplete or inaccurate, leaving tests as the closest thing to a specification.

scopelint spec embraces this philosophy of "your tests are your spec" to help developers come up with a spec with minimal effort. If you structure your test contracts and test names as described in the Best Practices guide scopelint spec will generate a specification for you! This specification can be shared with other stakeholders to make sure everyone is on the same page about what the contract should do.

Below is a simple example for an ERC-20 token, the full example repo can be found here.

scopelint-spec

Currently this feature is in beta, and we are looking for feedback on how to improve it. Right now it's focused on specifications for unit tests, which are very useful for developers but less useful for higher-level stakeholders. As a result, it does not yet include information about protocol invariants or integration test / user-story types of specifications. If you have any thoughts or ideas, please open an issue here.

Foundry Template

The Foundry Template is a project template for Solidity development that includes several features to help developers write secure, auditable contracts. It includes a robust CI template which provides the following out of the box:
  • Tests: Tests are run using the included ci profile.
  • Size checks: A CI job checks that contracts are within the size limit.
  • Scopelint: scopelint check is run to validate formatting and conventions.
  • Coverage: A coverage report is generated and posted to the PR as a comment. Additionally, a minimum coverage threshold can be set to fail CI if coverage drops below a certain threshold.
  • Slither: This powerful static analyzer by Trail of Bits is run to detect common security vulnerabilities. It's integrated with GitHub's code scanning feature, so you can see the results in the security tab of your repo.

Additionally, tests are structured to run against your deploy script. This ensures that even if you forget to add tests for your deploy script, your tests will run against the same environment that results from your deploy script.

The repo README contains more details about each feature and information on how to customize the template for your needs.