/solidity-audit-template

Combines Hardhat, TypeChain, Ethers, Waffle, Solhint, Solcover, Prettier, Tracer, storage layout analysis, EVM network forking, Immunefi/Etherscan contract download and external contract testing

Primary LanguageTypeScriptMIT LicenseMIT

Solidity Coding, Testing and Audit Template Open in Gitpod Hardhat License: MIT

My favorite setup for writing Solidity smart contracts as well as auditing/testing external contracts.

  • Hardhat: compile, run and test smart contracts on a local development network
  • TypeChain: generate TypeScript bindings for smart contracts
  • Ethers: renowned Ethereum library and wallet implementation
  • Solhint: code linter
  • Solcover: code coverage
  • Prettier Plugin Solidity: code formatter
  • Tracer: trace events, calls and storage operations
  • Storage Layout: generate smart contract storage layout
  • Fork the mainnet or another EVM based network as a Hardhat Network instance
  • Download external contracts and their dependencies (via Python script)
  • Gather contracts in scope from Immuenfi bug bounty (via Python script)
  • Attach tests to external contracts and impersonate accounts (in mainnet fork)

Getting Started

Click the Use this template button at the top of the page to create a new repository with this repo as the initial state.

Features

This template builds upon the frameworks and libraries mentioned above, so for details about their specific features, please consult their respective documentations.

For example, for Hardhat, you can refer to the Hardhat Tutorial and the Hardhat Docs. You might be in particular interested in reading the Testing Contracts section.

Sensible Defaults

This template comes with sensible default configurations in the following files:

├── .commitlintrc.yml
├── .editorconfig
├── .eslintignore
├── .eslintrc.yml
├── .gitignore
├── .prettierignore
├── .prettierrc.yml
├── .solcover.js
├── .solhintignore
├── .solhint.json
├── .yarnrc.yml
└── hardhat.config.ts

GitHub Actions

This template comes with GitHub Actions pre-configured (disabled per default). Your contracts will be linted and tested on every push and pull request made to the main branch.

Note though that to make this work, you must use your INFURA_API_KEY and your MNEMONIC as GitHub secrets and rename the CI script to ci.yml in order to enable it.

You can edit the CI script in .github/workflows/ci.yml.example.

Conventional Commits

This template enforces the Conventional Commits standard for git commit messages. This is a lightweight convention that creates an explicit commit history, which makes it easier to write automated tools on top of.

Git Hooks

This template uses Husky to run automated checks on commit messages, and Lint Staged to automatically format the code with Prettier when making a git commit.

Usage

Pre Requisites

Before being able to run any command, you need to create a .env file and set a BIP-39 compatible mnemonic as an environment variable. You can follow the example in .env.example. If you don't already have a mnemonic, you can use this website to generate one.

Then, proceed with installing dependencies:

$ yarn install
$ pip install -r contract-downloader/requirements.txt  # for Python contract downloader

Example usage: External contract testing

  1. Download external contract + dependencies or download contracts from Immunefi bug bounty
$ yarn clone <contract address>
# OR
$ yarn immunefi <bug bounty URL>
  1. Set Solidity version in hardhat.config.ts
  2. Compile contract(s) and generate typings
$ yarn compile
  1. Export the contracts' storage layouts
$ yarn storage
  1. Fork the mainnet as a local Hardhat Network instance
$ yarn fork
  1. Adapt the test templates to break/exploit the external contract in the local Hardhat Network instance
$ yarn attach <contract address>
$ yarn attachContract <contract address>

Compile

Compile the smart contracts with Hardhat:

$ yarn compile

TypeChain

Compile the smart contracts and generate TypeChain bindings:

$ yarn typechain

Test

Run the Mocha test for the example Greeter contract:

$ yarn test

Lint Solidity

Lint the Solidity code:

$ yarn lint:sol

Lint TypeScript

Lint the TypeScript code:

$ yarn lint:ts

Coverage

Generate the code coverage report:

$ yarn coverage

Report Gas

See the gas usage per unit test and average gas per method call:

$ REPORT_GAS=true
$ yarn test

Tracer

Shows events, calls and storage operations when running the tests:

$ yarn test --trace      # shows logs + calls
$ yarn test --fulltrace  # shows logs + calls + sloads + sstores

Storage Layout

Shows the compiled contracts' storage layouts:

$ yarn storage

Mainnet Fork

Starts an instance of Hardhat Network that forks mainnet. This means that it will simulate having the same state as mainnet, but it will work as a local development network. That way you can interact with deployed protocols and test complex interactions locally.

To use this feature you need to set your Infura API key in the .env file.

$ yarn fork
$ yarn fork --fork-block-number <num>  # pin the block number

Network Fork

Starts an instance of Hardhat Network that forks an EVM based network. Supported networks are given by chainIds[] in hardhat.config.ts.

$ yarn forkNetwork --network <chain>  # e.g. rinkeby or polygon-mainnet

Clone (with Python contract downloader)

Downloads a verified smart contract and its dependencies from Etherscan, etc. To use this feature you need to set the relevant API keys in the .env file.

$ yarn clone <contract address>
$ yarn clone <contract address> --network <chain>  # e.g. polygon or bsc

In order to remove a previously downloaded smart contract and its dependencies from the local filesystem, run:

$ yarn clone <contract address> --remove

Furthermore, implementation contracts can be downloaded through proxies by:

$ yarn clone <proxy contract address> --impl

Immunefi (with Python contract downloader)

Gathers all block explorer links to verified smart contracts in scope from an Immunefi bug bounty page and forwards them to the downloader, see Clone.

$ yarn immunefi <bug bounty URL>
$ yarn immunefi <bug bounty URL> --remove  #  delete contracts

Attach test to external contract

Attaches the Mocha test external/Attach to a deployed contract in your local Hardhat Network (e.g. mainnet fork). The test contains sample code for the Greeter contract and therefore needs to be adapted according to your needs.

$ yarn attach <contract address> [--impersonate <address>]

Features like Report Gas and Tracer can also be used with this test.

Attach test contract to external contract

Attaches the Mocha test external/AttachContract and the contract test/Test to a deployed contract in your local Hardhat Network (e.g. mainnet fork). The test contains sample code for the Greeter contract and therefore needs to be adapted according to your needs.

$ yarn attachContract <contract address> [--impersonate <address>]

Features like Report Gas and Tracer can also be used with this test.

Clean

Delete the smart contract artifacts, the coverage reports and the Hardhat cache:

$ yarn clean

Clean contracts

Delete all non-template contracts from the contract directory:

$ yarn cleanContracts

Clean all

Combines Clean and Clean contracts:

$ yarn cleanAll

Deploy

Deploy the example Greeter contract to the Hardhat Network:

$ yarn deploy --greeting "Hello, world!"

Tips

Syntax Highlighting

If you use VSCode, you can get Solidity syntax highlighting with the hardhat-solidity extension.

Using GitPod

GitPod is an open-source developer platform for remote development.

To view the coverage report generated by yarn coverage, just click Go Live from the status bar to turn the server on/off.

License

MIT © Paul Razvan Berg & Mario Poneder