My favorite setup for writing Solidity smart contracts as well as auditing/testing external contracts.
- Hardhat: compile and run the smart contracts on a local development network
- TypeChain: generate TypeScript types for smart contracts
- Ethers: renowned Ethereum library and wallet implementation
- Waffle: tooling for writing comprehensive smart contract tests
- Solhint: 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 (in mainnet fork)
This is a GitHub template, which means you can reuse it as many times as you want. You can do that by clicking the "Use this template" button at the top of the page.
Before running any command, you need to create a .env
file and set a BIP-39 compatible mnemonic as an environment
variable. Follow the example in .env.example
. If you don't already have a mnemonic, use this website to generate one.
Then, proceed with installing dependencies:
$ yarn install
$ pip install -r contract-downloader/requirements.txt # for Python contract downloader
- Download external contract + dependencies or download contracts from Immunefi bug bounty
$ yarn clone <contract address>
# OR
$ yarn immunefi <bug bounty URL>
- Set Solidity version in
hardhat.config.ts
- Compile contract(s) and generate typings
$ yarn compile
- Export the contracts' storage layouts
$ yarn storage
- Fork the mainnet as a local Hardhat Network instance
$ yarn fork
- 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 the smart contracts with Hardhat:
$ yarn compile
Compile the smart contracts and generate TypeChain artifacts:
$ yarn typechain
Lint the Solidity code:
$ yarn lint:sol
Lint the TypeScript code:
$ yarn lint:ts
Run the Mocha test for the example Greeter contract:
$ yarn test
Generate the code coverage report:
$ yarn coverage
See the gas usage per unit test and average gas per method call:
$ REPORT_GAS=true
$ yarn test
Shows events, calls and storage operations when running the tests:
$ yarn test --trace # shows logs + calls
$ yarn test --fulltrace # shows logs + calls + sloads + sstores
Shows the compiled contracts' storage layouts:
$ yarn storage
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
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
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
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
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>
Features like Report Gas and Tracer can also be used with this test.
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>
Features like Report Gas and Tracer can also be used with this test.
Delete the smart contract artifacts, the coverage reports and the Hardhat cache:
$ yarn clean
Deploy the example Greeter contract to the Hardhat Network:
$ yarn deploy --greeting "Hello, world!"
If you use VSCode, you can enjoy syntax highlighting for your Solidity code via the hardhat-vscode extension.
If you can't get the Waffle matchers to work, try to
make your ethers
package version match the version used by the @ethereum-waffle/chai
package. Seem
#111 for more details.