-
Notifications
You must be signed in to change notification settings - Fork 98
Add "Getting started" guide #10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 15 commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
a918c8b
Add "Getting started" guide draft
fvictorio 023bfa5
Simplify the project initialization
alcuadrado 76e3baf
Some wording improvements in the project description
alcuadrado 008494e
Remove the Running a task section (for now) and add one about writing…
alcuadrado 0ab3d1f
Explain what cheatcodes are
alcuadrado 86e1756
Add a bit more of info about TS tests in the general intro
alcuadrado 74b5a9a
Explain that you can run all the tests with `hardhat test`
alcuadrado 2c96f9b
Explain that `test solidity` compiles your contracts and tests
alcuadrado 2abaa41
Small wording improvements
alcuadrado 6b3c1a3
Add missing link
alcuadrado 5c3da89
Add another reason to use TS
alcuadrado 4d1c675
Explain that `test node` is to only run node:test
alcuadrado 047e43a
Wording improvement and a closing to TS tests
alcuadrado 12a9e57
Remove a TODO item
alcuadrado 0a9968f
Add a learn more section and a TODO comment
alcuadrado 279884e
Update src/content/hardhat3-alpha/learn-more/getting-started.md
alcuadrado c9dbf30
Add 3 to the title
alcuadrado 22f4e5f
Add "Using scripts" section
fvictorio 0c2d63f
"Deploying contracts" draft
fvictorio ba8c0bb
Copy the existing Ignition explanation to its own guide
alcuadrado d506986
Reorder the Learn more dirinfo
alcuadrado bd61787
Swap the old getting started for the new one, and leave the old one a…
alcuadrado 7f0753d
Small fixes to the deployment guide
alcuadrado fb77e09
Add markdown links linter
alcuadrado 25f358a
Fix broken links
alcuadrado 6cd7b2c
Update the banner for ETHPrage
alcuadrado b910505
Small wording fix
alcuadrado 0bbd17d
Update AlphaBanner
alcuadrado File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
388 changes: 388 additions & 0 deletions
388
src/content/hardhat3-alpha/learn-more/getting-started.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,388 @@ | ||
| --- | ||
| prev: true | ||
| --- | ||
|
|
||
| # Getting started with Hardhat | ||
|
|
||
| Hardhat is a flexible and extensible development environment for Ethereum software. It helps you write, test, debug and deploy your smart contracts with ease, whether you're building a simple prototype or a complex production system. | ||
|
|
||
| This guide will walk you through the installation of our recommended setup, but as most of Hardhat's functionality comes from plugins, you are free to customize it or choose a completely different path. | ||
|
|
||
| ## Installation | ||
|
|
||
| :::tip | ||
|
|
||
| [Hardhat for Visual Studio Code](/hardhat-vscode) is the official Hardhat extension that adds advanced support for Solidity to VSCode. If you use Visual Studio Code, give it a try! | ||
|
|
||
| ::: | ||
|
|
||
| To get started with Hardhat 3, you’ll need [Node.js](https://nodejs.org/) v22 or later installed on your system, along with a package manager such as [npm](https://www.npmjs.com/) or [pnpm](https://pnpm.io/). | ||
|
|
||
| First, create a new directory for your project: | ||
|
|
||
| ```bash | ||
| mkdir hardhat-example | ||
| cd hardhat-example | ||
| ``` | ||
|
|
||
| Once that's done, initialize your Hardhat project by running: | ||
|
|
||
| ::::tabsgroup{options=npm,pnpm} | ||
|
|
||
| :::tab{value=npm} | ||
|
|
||
| ```bash | ||
| npx hardhat@next --init | ||
| ``` | ||
|
|
||
| ::: | ||
|
|
||
| :::tab{value=pnpm} | ||
|
|
||
| ```bash | ||
| pnpm dlx hardhat@next --init | ||
| ``` | ||
|
|
||
| ::: | ||
|
|
||
| :::: | ||
|
|
||
| This command will prompt you with a few configuration options. You can accept the default answers to quickly scaffold a working setup. | ||
|
|
||
| Using the defaults will: | ||
|
|
||
| 1. Initialize the project in the current directory. | ||
| 2. Use the example project that includes the [Node.js test runner](https://nodejs.org/api/test.html) and [viem](https://viem.sh/). | ||
| 3. Automatically install all the required dependencies. | ||
|
|
||
| After the setup is complete, you’ll have a fully working Hardhat 3 project with everything you need to get started. Run the Hardhat help to verify the project was set up correctly: | ||
|
|
||
| ::::tabsgroup{options=npm,pnpm} | ||
|
|
||
| :::tab{value=npm} | ||
|
|
||
| ```bash | ||
| npx hardhat --help | ||
| ``` | ||
|
|
||
| ::: | ||
|
|
||
| :::tab{value=pnpm} | ||
|
|
||
| ```bash | ||
| pnpm hardhat --help | ||
| ``` | ||
|
|
||
| ::: | ||
|
|
||
| :::: | ||
|
|
||
| ## Project structure | ||
|
|
||
| The Hardhat project initialization from the previous section creates the following file structure: | ||
|
|
||
| ``` | ||
| hardhat.config.ts | ||
|
|
||
| contracts | ||
| ├── Counter.sol | ||
| └── Counter.t.sol | ||
|
|
||
| test | ||
| └── Counter.ts | ||
|
|
||
| ignition | ||
| └── modules | ||
| └── Counter.ts | ||
|
|
||
| scripts | ||
| ├── check-predeploy.ts | ||
| └── send-op-tx.ts | ||
| ``` | ||
|
|
||
| Here’s a quick overview of these files and directories: | ||
|
|
||
| - `hardhat.config.ts`: The main configuration file for your project. It defines settings like the Solidity compiler version, network configurations, and the plugins and tasks your project uses. | ||
|
|
||
| - `contracts`: Contains your project's Solidity contracts. You can also include Solidity test files here. Any file ending in `.t.sol` will be treated as a test file. | ||
|
|
||
| - `test`: Used for TypeScript integration tests. You can also include Solidity test files here. | ||
|
|
||
| - `ignition`: Holds your [Hardhat Ignition](https://hardhat.org/ignition) deployment modules, which describe how your contracts should be deployed. | ||
|
|
||
| - `scripts`: A place for any custom scripts that interact with your contracts or automate parts of your workflow. Scripts have full access to Hardhat’s runtime and can use plugins, connect to networks, deploy contracts, and more. | ||
|
|
||
| ## Writing a smart contract | ||
|
|
||
| Writing a smart contract with Hardhat is as easy as writing a Solidity file inside the `contracts` directory. For example, your `contracts/Counter.sol` should look like this: | ||
|
|
||
| ```solidity | ||
| pragma solidity ^0.8.28; | ||
|
|
||
| contract Counter { | ||
| uint public x; | ||
|
|
||
| event Increment(uint by); | ||
|
|
||
| function inc() public { | ||
| x++; | ||
| emit Increment(1); | ||
| } | ||
|
|
||
| function incBy(uint by) public { | ||
| require(by > 0, "incBy: increment should be positive"); | ||
| x += by; | ||
| emit Increment(by); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| Hardhat will automatically detect it, and compile it with the correct version of Solidity based on its `pragma` statment and your Hardhat configuration. All you need to do is running: | ||
|
alcuadrado marked this conversation as resolved.
Outdated
|
||
|
|
||
| ::::tabsgroup{options=npm,pnpm} | ||
|
|
||
| :::tab{value=npm} | ||
|
|
||
| ```bash | ||
| npx hardhat compile | ||
| ``` | ||
|
|
||
| ::: | ||
|
|
||
| :::tab{value=pnpm} | ||
|
|
||
| ```bash | ||
| pnpm hardhat compile | ||
| ``` | ||
|
|
||
| ::: | ||
|
|
||
| :::: | ||
|
|
||
| You can learn more about how to customize your Solidity version and settings in [this guide](./configuring-the-compiler.md). | ||
|
|
||
| ## Testing your contracts | ||
|
|
||
| Tests are a critical part of any Ethereum project. Hardhat lets you write tests in both **Solidity** and **TypeScript**, giving you flexibility to choose the right tool for each situation. | ||
|
|
||
| Solidity tests run directly on the EVM and are great for unit tests. They execute in a controlled environment, making them fast and deterministic. They also have access to test-related EVM extensions, normally called cheatcodes, which allow you to build complex tests in Solidity. | ||
|
|
||
| TypeScript tests, on the other hand, use a fully-simulated local blockchain and interact with it through JSON-RPC. This allows you to write more complex or end-to-end tests using the full power of a general-purpose programming language and a realistic blockchain simulation. You can use any Ethereum TypeScript library, like [viem](https://viem.sh/) or [ethers.js](https://docs.ethers.org/v5/) to write your tests. | ||
|
|
||
| Use Solidity when you want low-level, efficient, EVM-native tests. Use TypeScript when you want richer tooling, more flexible assertions, or to test blockchain-level interactions, like workflows involving multiple transactions. | ||
|
|
||
| ### Solidity tests | ||
|
|
||
| Hardhat 3 has full support for writing Solidity tests. The example project includes a Solidity test file at `contracts/Counter.t.sol`: | ||
|
|
||
| ```solidity | ||
| import { Counter } from "./Counter.sol"; | ||
| import { Test } from "forge-std/Test.sol"; | ||
|
|
||
| contract CounterTest is Test { | ||
| Counter counter; | ||
|
|
||
| function setUp() public { | ||
| counter = new Counter(); | ||
| } | ||
|
|
||
| function test_InitialValue() public view { | ||
| require(counter.x() == 0, "Initial value should be 0"); | ||
| } | ||
|
|
||
| function testFuzz_Inc(uint8 x) public { | ||
| for (uint8 i = 0; i < x; i++) { | ||
| counter.inc(); | ||
| } | ||
| require(counter.x() == x, "Value after calling inc x times should be x"); | ||
| } | ||
|
|
||
| function test_IncByZero() public { | ||
| vm.expectRevert(); | ||
| counter.incBy(0); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| You can run all the test in your project — both Solidity and TypeScript — using the `test` task: | ||
|
|
||
| ::::tabsgroup{options=npm,pnpm} | ||
|
|
||
| :::tab{value=npm} | ||
|
|
||
| ```bash | ||
| npx hardhat test | ||
| ``` | ||
|
|
||
| ::: | ||
|
|
||
| :::tab{value=pnpm} | ||
|
|
||
| ```bash | ||
| pnpm hardhat test | ||
| ``` | ||
|
|
||
| ::: | ||
|
|
||
| :::: | ||
|
|
||
| If you only want to run your Solidity tests, you can use this instead: | ||
|
|
||
| ::::tabsgroup{options=npm,pnpm} | ||
|
|
||
| :::tab{value=npm} | ||
|
|
||
| ```bash | ||
| npx hardhat test solidity | ||
| ``` | ||
|
|
||
| ::: | ||
|
|
||
| :::tab{value=pnpm} | ||
|
|
||
| ```bash | ||
| pnpm hardhat test solidity | ||
| ``` | ||
|
|
||
| ::: | ||
|
|
||
| :::: | ||
|
|
||
| When you run this command, Hardhat will: | ||
|
|
||
| - Compile your contracts and tests. | ||
| - Treat all `.t.sol` files in the `contracts/` directory and all `.sol` files in the `test/` directory as test files. | ||
| - Deploy each test contract defined in those files. | ||
| - Call every function that starts with `test`. If any of these calls revert, the corresponding test is marked as failed. | ||
|
|
||
| In the example above: | ||
|
|
||
| - `test_InitialValue` and `test_IncByZero` are **unit tests**: they take no parameters and run once per test execution. | ||
| - `testFuzz_Inc` is a **fuzz test**: since it takes a parameter, Hardhat will run it multiple times using random inputs. If any of those runs revert, the fuzz test fails and the failing input is printed. | ||
|
|
||
| If any of your tests fails, Hardhat will provide detailed **Solidity stack traces** to help you understand why. To see them in action, first comment out the `vm.expectRevert();` line in `test_IncByZero`: | ||
|
|
||
| ```solidity | ||
| function test_IncByZero() public { | ||
| // vm.expectRevert(); | ||
| counter.incBy(0); | ||
| } | ||
| ``` | ||
|
|
||
| Then run the last command again and you’ll get a stack-trace along with the test failure: | ||
|
|
||
| ``` | ||
| Failure (1): test_IncByZero() | ||
| Reason: revert: incBy: increment should be positive | ||
| at Counter.incBy (contracts/Counter.sol:15) | ||
| at CounterTest.test_IncByZero (contracts/Counter.t.sol:30) | ||
| ``` | ||
|
|
||
| This lets you quickly pinpoint the issue, even across deeply nested calls. | ||
|
|
||
| Learn more at [writing Solidity tests here](./writing-solidity-tests.md). | ||
|
|
||
| ### TypeScript tests | ||
|
|
||
| Solidity tests are ideal for fast, focused unit testing, but they fall short in certain situations: | ||
|
|
||
| - **Complex test logic**, where a general-purpose language like TypeScript is more expressive and ergonomic than Solidity. | ||
| - **Tests that require realistic blockchain behavior**, such as advancing blocks or working with gas costs or multiple transactions. While cheatcodes can simulate this to some extent, excessive mocking is hard to maintain and can lead to inaccurate assumptions. | ||
| - **End-to-end scenarios**, where you want to test your contracts as they would behave in production—across multiple transactions, clients, and user interactions. | ||
|
|
||
| To support these cases, Hardhat lets you write tests in TypeScript (or JavaScript), using the Node.js test runner or other frameworks like Mocha. These tests run in a real Node.js environment and interact with your contracts through RPC, making them more representative of actual usage. | ||
|
|
||
| The example project includes a TypeScript test file at `test/Counter.ts`: | ||
|
|
||
| ```tsx | ||
| describe("Counter", async function () { | ||
| const { viem } = await network.connect(); | ||
| const publicClient = await viem.getPublicClient(); | ||
|
|
||
| it("The sum of the Increment events should match the current value", async function () { | ||
| const counter = await viem.deployContract("Counter"); | ||
|
|
||
| // run a series of increments | ||
| for (let i = 1n; i <= 10n; i++) { | ||
| await counter.write.incBy([i]); | ||
| } | ||
|
|
||
| const events = await publicClient.getContractEvents({ | ||
| address: counter.address, | ||
| abi: counter.abi, | ||
| eventName: "Increment", | ||
| fromBlock: 0n, | ||
| strict: true, | ||
| }); | ||
|
|
||
| // check that the aggregated events match the current value | ||
| let total = 0n; | ||
| for (const event of events) { | ||
| total += event.args.by; | ||
| } | ||
|
|
||
| assert.equal(total, await counter.read.x()); | ||
| }); | ||
| }); | ||
| ``` | ||
|
|
||
| To run only your TypeScript tests, use the `test node` task: | ||
|
|
||
| ::::tabsgroup{options=npm,pnpm} | ||
|
|
||
| :::tab{value=npm} | ||
|
|
||
| ```bash | ||
| npx hardhat test node | ||
| ``` | ||
|
|
||
| ::: | ||
|
|
||
| :::tab{value=pnpm} | ||
|
|
||
| ```bash | ||
| pnpm hardhat test node | ||
| ``` | ||
|
|
||
| ::: | ||
|
|
||
| :::: | ||
|
|
||
| This test deploys the `Counter` contract, calls `incBy` multiple times (each in a separate transaction), collects all the emitted `Increment` events, and verifies that their sum matches the contract's final value. | ||
|
|
||
| Writing this same test in Solidity is possible, but less convenient, and the test would be executed in a different context — closer to a single transaction calling the contract multiple times, than different users interacting with it over time. This makes TypeScript a better fit for scenarios that depend on realistic transaction flows or blockchain behavior. | ||
|
|
||
| You can write any TypeScript code you want in your tests, as they are normal TypeScript files with access to Hardhat. In this example, we use `viem` to interact with the contracts and test the expected behavior. To learn more about how to use `viem` with Hardhat, read [this guide](./using-viem.md). | ||
|
|
||
| ## Using scripts | ||
|
|
||
| - What scripts are | ||
| - Example script | ||
|
|
||
| ## Deploying contracts | ||
|
|
||
| - Short explanation about Ignition | ||
| - Example module explanation | ||
| - Running a deployment in a Hardhat node | ||
| - Connecting a wallet to a Hardhat node | ||
|
|
||
| ## Learn more | ||
|
|
||
| To learn more about Hardhat, check out these other guides: | ||
|
|
||
| - [Writing Solidity tests](../learn-more/writing-solidity-tests.md) | ||
| - [Using Viem with Hardhat](../learn-more/using-viem.md) | ||
| - [Configuring the compiler](../learn-more/configuring-the-compiler.md) | ||
| - [Differences with Hardhat 2](../learn-more/comparison.md) | ||
|
|
||
| and join our [Hardhat 3 Alpha](https://hardhat.org/hardhat3-alpha-telegram-group) Telegram group to share feedback and stay updated on new releases. | ||
|
|
||
| <!-- | ||
|
|
||
| TODO: | ||
|
|
||
| - Code coverage | ||
| - Viem assertions | ||
| - Verification | ||
|
|
||
| --> | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.