This document contains some tips on how to collaborate in this project.
If you find a bug or want to propose a new feature, please open an issue. Pull requests are welcome, but we recommend you discuss it in an issue first, especially for big changes. This will increase the odds that we can accept your PR.
We use a GitHub project to triage new issues and plan our work. You can check our list of good first issues there.
This repository is a monorepo handled with pnpm and pnpm workspaces.
There's a folder for each subproject in packages/. All of them are plugins, except for /packages/hardhat-core which is the main project (i.e. the one that's published as hardhat in npm).
To install the project's dependencies, run pnpm i in the root directory of the repository.
Plugins require hardhat to be built or tested. Our recommendation is to run pnpm build from the root folder.
All tests are written using node test runner.
You can run a package's tests by executing pnpm test inside its folder.
You can run all the tests at once by running pnpm test from the root folder.
We use Prettier to format all the code without any special configuration. Whatever Prettier does is considered The Right Thing. It's completely fine to commit non-prettied code and then reformat it in a later commit.
We also have eslint installed in all the projects. It checks that you have run Prettier and forbids some dangerous patterns.
The linter is always run in the CI, so make sure it passes before pushing code. You can use pnpm lint and pnpm lint:fix inside the packages' folders.
We work on two branches, main and development.
The main branch is meant to be kept in sync with the latest released version of each package. Most pull requests are based on main, so when in doubt use this branch.
The development branch is meant to be used for major, risky changes that are ready, but we can't or don't want to release yet. We never release new versions from development. When we want to release the changes from development, we go through a stricter QA process, merge those changes into main, and release from main. Examples of things that should be based on development are features that require significant changes to the codebase, or bug fixes that involve a major refactor.
If you are modifying the default config, adding a feature, or doing any kind of technical work that should be reflected in the documentation, the documentation change should be contained in the same branch and PR as the change.
If you are working purely on the website or documentation, not as a result of a technical change, you should branch from main and use it as the base branch in your pull request.
Note that the main branch is automatically deployed, so take care when merging into it.
We keep our dependencies versions in sync between the different projects.
Running node scripts/check-dependencies.js from the root folder checks that every project specifies the same versions of each dependency. It will print an error if the versions get out of sync.
Hardhat and its plugins are optimized for keeping startup time low.
This is done by selectively requiring dependencies when needed using import or require following this criteria:
- If something is only imported for its type, and NOT its value, use a top-level
import ... from "mod". - If a module is in the "Essential modules" list below, use a top-level
import ... from "mod". - Otherwise, use
await importorrequirelocally in the functions that use it:- If the function is sync, use node's
require - If the function is an async, use
await import
- If the function is sync, use node's
Note that these rules don't apply to tests. You can always use top-level imports there.
This is a list of the modules that always get loaded during startup:
fspathutilfind-upfs-extrachalksemversource-map-support/register
The project can be built by pnpm build from the root directory.
You can link any package to test it locally. While the rest of the commands we run use pnpm, we recommend you use npm for linking. For example, if you are working on hardhat, you can follow these steps:
- Go to
packages/hardhat-coreand runnpm link - Go to some hardhat project and run
npm link hardhat
Now any change you make in the code will be reflected in that project.
If for any reason linking doesn't work for you, you can use yalc:
- Go to
packages/hardhat-coreand runyalc publish - Go to some hardhat project and run
yalc add hardhat
Unlike linking, if you make a change in the code, you'll need to repeat the process.
An even more realistic way of using your local changes in a project is to use pnpm pack:
- Go to
packages/hardhat-coreand runpnpm pack. This will create ahardhat-x.y.z.tgzfile in that directory. - Go to some hardhat project and run
npm install /path/to/hardhat/packages/hardhat-core/hardhat-x.y.z.tgz.
Unlike linking, if you make a change in the code, you'll need to repeat the process.
If you want to debug something, you can use ndb. First add a debugger statement wherever you want. Then link your project. Finally, run hardhat as normally but prepend the command with ndb. For example, you can do ndb npx hardhat compile to debug some part of the compile task.
You should avoid monkey-patching whenever possible. But if it's necessary to do so, you should pay extra care when doing it in a Hardhat plugin or your tests may fail in very hard to debug ways.
When tests are run, Hardhat gets initialized multiple times, and that means unloading and reloading config and plugin modules. This unloading process may or may not lead to your dependencies being reloaded. This makes monkey-patching harder, as you may apply the same patch multiple times to the same module.
This problem is normally not present if you are monkey-patching an object that you initialized, but it is when monkey-patching a class, its prototype, or a singleton object initialized by the library itself.
For an example on how to do it properly, please take a look at the hardhat-truffle5 plugin.
We generally really appreciate external contributions, and strongly encourage meaningful additions and fixes! However, due to a recent increase in small PRs potentially created to farm airdrops, we might need to close a PR without explanation if any of the following apply:
- It is a change of very minor value that still requires additional review time/fixes (e.g. PRs fixing trivial spelling errors that can’t be merged in less than a couple of minutes due to incorrect suggestions)
- It introduces inconsequential changes (e.g. rewording phrases)
- The author of the PR does not respond in a timely manner
- We suspect the Github account of the author was created for airdrop farming
Shortlist of steps that should be always considered when committing changes. All errors reported by any command must be resolved before moving ahead.
All commands expect that they are executed from the root of the repository.
pnpm build- build the entire projectpnpm lint- check formatting and code structurepnpm lint:fix- fix formatting issuespnpm test- run all tests
Commit changes and create a PR once all the commands above are successful. The CI pipeline would block the PR otherwise.
- Create a branch for the change
- there is a
Create a branchoption in theDevelopmentsection in case the change is tracked by an issue
- there is a
- Create a PR from the new branch to
main- Add description that explains the change