Skip to content
This repository was archived by the owner on Oct 3, 2024. It is now read-only.

Commit f44052d

Browse files
chore: testing smart contracts using hardhat plugins (#902)
1 parent 9a5ba49 commit f44052d

File tree

2 files changed

+342
-0
lines changed

2 files changed

+342
-0
lines changed

docs/.vuepress/sidebar/en.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,10 @@ export const enSidebar = sidebar({
170170
text: "Verify Contracts with Hardhat",
171171
link: "/build/tutorials/how-to/verify-contracts.md"
172172
},
173+
{
174+
text: "Test Contracts with Hardhat",
175+
link: "/build/tutorials/how-to/test-contracts.md"
176+
},
173177
],
174178
},
175179
]
Lines changed: 338 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,338 @@
1+
---
2+
head:
3+
- - meta
4+
- name: "twitter:title"
5+
content: Test Contracts on zkSync with Hardhat | zkSync Docs
6+
---
7+
8+
# Test smart contracts with Hardhat plugins
9+
10+
This tutorial provides a step-by-step guide on testing smart contracts using the **hardhat-zksync-chai-matchers** plugin in conjunction with the **zkSync Era Test Node** on your local machine. To facilitate this process of running tests on the **zkSync Era Test Node**, you'll also utilize the **hardhat-zksync-node** plugin.
11+
12+
# Prerequisites
13+
14+
- Node.js installed (version 14.x or later)
15+
- Either yarn or npm installed
16+
- Initialized Hardhat TypeScript project
17+
18+
# Tutorial
19+
20+
## Integration with hardhat-zksync-node plugin
21+
22+
In this tutorial, the contract functionality is tested using the [zkSync Era Test Node](../../test-and-debug/era-test-node.md). To start local node we use a **hardhat-zksync-node** plugin to integrate this functionality within the Hardhat project.
23+
24+
:::warning zkSync Era Test Node alpha phase
25+
26+
During the alpha phase, zkSync Era Test Nodes are currently undergoing development, wherein certain functionalities might not be fully supported or operational.
27+
28+
:::
29+
30+
### Installation
31+
32+
To install the **hardhat-zksync-node** plugin and additional necessary packages, execute the following command:
33+
34+
::: code-tabs
35+
36+
@tab:active yarn
37+
38+
```bash
39+
yarn add -D @matterlabs/hardhat-zksync-node
40+
```
41+
42+
@tab npm
43+
44+
```bash
45+
npm i -D @matterlabs/hardhat-zksync-node
46+
```
47+
48+
:::
49+
50+
Once installed, add the plugin at the top of your **hardhat.config.ts** file.
51+
52+
```bash
53+
import "@matterlabs/hardhat-zksync-node";
54+
```
55+
56+
### Starting the zkSync Era Test Node
57+
58+
You can now safely run the **zkSync Era Test Node** with the following command, ensuring proper execution:
59+
60+
```bash
61+
yarn hardhat node-zksync
62+
```
63+
64+
::: note Test if all is ok
65+
66+
We'll want to verify the correctness of our installations and test if we can run a **zkSync Era Test Node**, without further use of this command in the tutorial.
67+
68+
:::
69+
70+
You should see output similar to this:
71+
72+
```log
73+
09:04:44 INFO Account #9: 0xe2b8Cb53a43a56d4d2AB6131C81Bd76B86D3AFe5 (1_000_000_000_000 ETH)
74+
09:04:44 INFO Private Key: 0xb0680d66303a0163a19294f1ef8c95cd69a9d7902a4aca99c05f3e134e68a11a
75+
09:04:44 INFO Mnemonic: increase pulp sing wood guilt cement satoshi tiny forum nuclear sudden thank
76+
09:04:44 INFO
77+
09:04:44 INFO ========================================
78+
09:04:44 INFO Node is ready at 127.0.0.1:8011
79+
09:04:44 INFO ========================================
80+
```
81+
82+
Since we've confirmed that the **zkSync Era Test Node** is functioning properly with the help of the **hardhat-zksync-node** plugin, we can shut it down and continue with the tutorial.
83+
84+
Read more about **hardhat-zksync-node** [here.](../../tooling/hardhat/hardhat-zksync-node.md)
85+
86+
## Integration with hardhat-zksync-chai-matchers plugin
87+
88+
To leverage zkSync-specific capabilities within the [Chai](https://www.chaijs.com/) assertion library for testing smart contracts, it's necessary to use the **hardhat-zksync-chai-matchers** plugin.
89+
90+
### Installation
91+
92+
In the root directory of your project, execute this command:
93+
94+
::: code-tabs
95+
96+
@tab:active yarn
97+
98+
```bash
99+
yarn add -D @matterlabs/hardhat-zksync-chai-matchers @nomicfoundation/hardhat-chai-matchers chai @nomiclabs/hardhat-ethers ethers
100+
```
101+
102+
@tab npm
103+
104+
```bash
105+
npm i -D @matterlabs/hardhat-zksync-chai-matchers
106+
```
107+
108+
:::
109+
110+
After installing it, add the plugin at the top of your **hardhat.config.ts** file:
111+
112+
```bash
113+
import "@nomicfoundation/hardhat-chai-matchers"
114+
import "@matterlabs/hardhat-zksync-chai-matchers";
115+
```
116+
117+
::: note Import order matters
118+
119+
To enable the **@matterlabs/hardhat-zksync-chai-matchers** plugin to override **@nomicfoundation/hardhat-chai-matchers**, you must import the latter first, ensuring that all zkSync-specific matchers take override the original ones.
120+
121+
:::
122+
123+
Read more about **hardhat-zksync-chai-matchers** [here.](../../tooling/hardhat/hardhat-zksync-chai-matchers.md)
124+
125+
### Smart Contract creation
126+
127+
To set up the environment for using chai matchers and writing tests, you'll need to create some contracts. Follow these steps:
128+
129+
1. Navigate to the root of your project.
130+
2. Create a folder named **contracts**.
131+
3. Inside the **contracts** folder, create a file named **Greeter.sol**.
132+
133+
Now we should add some code to the new **Greeter.sol** file:
134+
135+
```solidity
136+
// SPDX-License-Identifier: MIT
137+
pragma solidity ^0.8.17;
138+
139+
contract Greeter {
140+
string private greeting;
141+
bool private greetingChanged;
142+
constructor(string memory _greeting) {
143+
greeting = _greeting;
144+
greetingChanged = false;
145+
}
146+
function greet() public view returns (string memory) {
147+
return greeting;
148+
}
149+
function setGreeting(string memory _greeting) public {
150+
require(bytes(_greeting).length > 0, "Greeting must not be empty");
151+
greeting = _greeting;
152+
greetingChanged = true;
153+
}
154+
function isGreetingChanged() public view returns (bool) {
155+
return greetingChanged;
156+
}
157+
}
158+
```
159+
160+
### Compiler configuration
161+
162+
We'll require the **hardhat-zksync-solc** plugin to compile our smart contracts. To install it, execute:
163+
164+
::: code-tabs
165+
166+
@tab:active yarn
167+
168+
```bash
169+
yarn add -D @matterlabs/hardhat-zksync-solc
170+
```
171+
172+
@tab npm
173+
174+
```bash
175+
npm i -D @matterlabs/hardhat-zksync-solc
176+
```
177+
178+
:::
179+
180+
Add the plugin at the top of your **hardhat.config.ts** file:
181+
182+
```bash
183+
import "@matterlabs/hardhat-zksync-solc";
184+
```
185+
186+
Customize the configuration options for the **hardhat-zksync-solc** plugin according to your requirements.
187+
188+
You can find more details about available configuration options in the [official documentation.](../../tooling/hardhat/hardhat-zksync-solc.md)
189+
190+
### Deploy configuration
191+
192+
We'll use provided example contract for testing with help of **hardhat-zksync-chai-matchers** plugin and deploying it on **zkSync Era Test Node**. Since deployment is involved, we'll also require the **hardhat-zksync-deploy** plugin for assistance. In the same directory, execute the command to install **hardhat-zksync-deploy** plugin:
193+
194+
::: code-tabs
195+
196+
@tab:active yarn
197+
198+
```bash
199+
yarn add -D @matterlabs/hardhat-zksync-deploy ethers zksync-ethers
200+
```
201+
202+
@tab npm
203+
204+
```bash
205+
npm i -D @matterlabs/hardhat-zksync-deploy
206+
```
207+
208+
:::
209+
210+
Add the **hardhat-zksync-deploy** plugin to your hardhat.config.ts file, you can import it as follows:
211+
212+
```bash
213+
import "@matterlabs/hardhat-zksync-deploy";
214+
```
215+
216+
Learn more about the **hardhat-zksync-deploy** plugin [here.](../../tooling/hardhat/hardhat-zksync-deploy.md)
217+
218+
## Write Test Cases
219+
220+
With the previous steps completed, your **hardhat.config.ts** file should now be properly configured to include settings for local testing.
221+
222+
```javascript
223+
import { HardhatUserConfig } from "hardhat/config";
224+
225+
import "@matterlabs/hardhat-zksync-solc";
226+
import "@matterlabs/hardhat-zksync-deploy";
227+
import "@matterlabs/hardhat-zksync-node";
228+
import "@nomicfoundation/hardhat-chai-matchers";
229+
import "@matterlabs/hardhat-zksync-chai-matchers";
230+
231+
const config: HardhatUserConfig = {
232+
zksolc: {
233+
version: "latest",
234+
},
235+
solidity: "0.8.19",
236+
networks: {
237+
hardhat: {
238+
zksync: true,
239+
},
240+
},
241+
};
242+
export default config;
243+
```
244+
245+
Here are the steps to create test cases with the **hardhat-zksync-chai-matchers** plugin:
246+
247+
1. Navigate to your project's root directory.
248+
2. Create a new folder named **test**.
249+
3. Inside the **test** folder, create a file named **test.ts**.
250+
251+
Once you've completed these steps, you'll be ready to write your tests using the **hardhat-zksync-chai-matchers** plugin.
252+
253+
Here's a brief example showcasing the functionalities of our contract:
254+
255+
```typescript
256+
import * as hre from "hardhat";
257+
import { expect } from "chai";
258+
import { Wallet, Provider, Contract } from "zksync-ethers";
259+
import { Deployer } from "@matterlabs/hardhat-zksync-deploy";
260+
import { ZkSyncArtifact } from "@matterlabs/hardhat-zksync-deploy/src/types";
261+
import { ZkSyncProviderAdapter } from "@matterlabs/hardhat-zksync-node";
262+
import "@matterlabs/hardhat-zksync-node/dist/type-extensions";
263+
264+
const RICH_PRIVATE_KEY = "0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110";
265+
266+
describe("Greeter", function () {
267+
let provider: Provider;
268+
let deployer: Deployer;
269+
let artifact: ZkSyncArtifact;
270+
let contract: Contract;
271+
272+
before(async function () {
273+
// Creation of a provider from a network URL adjusted specifically for the zkSync Era Test Node.
274+
provider = new Provider(hre.network.config.url);
275+
// To ensure proper testing, we need to deploy our contract on the zkSync Era Test Node, for more info check hardhat-zksync-deploy plugin documentation.
276+
deployer = new Deployer(hre, new Wallet(RICH_PRIVATE_KEY));
277+
artifact = await deployer.loadArtifact("Greeter");
278+
contract = await deployer.deploy(artifact, ["Hello, world!"]);
279+
});
280+
it("should work on Era Test node", async function () {
281+
const netVersion = await provider.send("net_version", []);
282+
expect(netVersion === 260);
283+
});
284+
it("greet should return a string", async function () {
285+
expect(await contract.greet()).to.be.a("string");
286+
});
287+
it("is deployed address valid", async function () {
288+
expect(await contract.getAddress()).to.be.properAddress;
289+
});
290+
it("greet should say Hello", async function () {
291+
expect(await contract.greet()).to.match(/^Hello/);
292+
});
293+
it("setGreeting should throw when passed an invalid argument", async function () {
294+
await expect(contract.setGreeting("")).to.be.revertedWith("Greeting must not be empty");
295+
});
296+
it("isGreetingChanged should return true after setting greeting", async function () {
297+
expect(await contract.isGreetingChanged()).to.be.false;
298+
const tx = await contract.setGreeting("Changed");
299+
await tx.wait();
300+
expect(await contract.greet()).to.match(/^Changed/);
301+
expect(await contract.isGreetingChanged()).to.be.true;
302+
});
303+
});
304+
```
305+
306+
Execute the following command in your terminal to run the tests:
307+
308+
```bash
309+
yarn hardhat test
310+
```
311+
312+
::: note When you execute this command, the contract will be automatically compiled, eliminating the need for manual compilation. However, if you prefer to compile manually, simply run the following command:
313+
314+
```bash
315+
yarn hardhat compile
316+
```
317+
318+
:::
319+
320+
The **hardhat-zksync-node** plugin overrides the default behavior of the Hardhat **test** task. It starts the **zkSync Era Test Node** before running tests, executes the tests, and then automatically shuts down the node after the test cases are completed. Additionally, the plugin generates a log file named `era_test_node.log`, which indicates the node's activity and transactions made during the tests. Whenever you re-run the **test** command, the content of `era_test_node.log` is refreshed.
321+
This setup ensures that your tests are executed against a controlled environment, mimicking the behavior of a live network but in a local sandboxed context. It's a common practice to ensure that smart contracts behave as expected under various conditions before deploying them to a live network.
322+
323+
`era_test_node.log` file example:
324+
325+
```
326+
10:53:11 INFO
327+
10:53:11 INFO EthToken System Contract
328+
10:53:11 INFO Topics:
329+
10:53:11 INFO 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
330+
10:53:11 INFO 0x0000000000000000000000000000000000000000000000000000000000008001
331+
10:53:11 INFO 0x00000000000000000000000036615cf349d7f6344891b1e7ca7c72883f5dc049
332+
10:53:11 INFO Data (Hex): 0x000000000000000000000000000000000000000000000000000028e0ec2a9900
333+
10:53:11 INFO
334+
10:53:11 INFO Call: SUCCESS
335+
10:53:11 INFO Output: "0x0000000000000000000000000000000000000000000000000000000000000001"
336+
10:53:11 INFO === Console Logs:
337+
10:53:11 INFO === Call traces:
338+
```

0 commit comments

Comments
 (0)