Skip to content
This repository was archived by the owner on Mar 5, 2025. It is now read-only.

Commit 350ec0d

Browse files
authored
Merge branch '4.x' into ok/6746-Web3.js-Adapter-for-Wagmi-Implementation
2 parents 5e7126e + 95807a6 commit 350ec0d

File tree

7 files changed

+338
-1
lines changed

7 files changed

+338
-1
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ yarn add web3
4848

4949
## Useful links
5050

51-
- [Web3 tree shaking support guide](https://docs.web3js.org/guides/advanced/web3_tree_shaking_support_guide/)
51+
- [Web3 tree shaking support guide](https://docs.web3js.org/guides/advanced/tree_shaking/)
5252
- [React App Example](https://github.com/ChainSafe/web3js-example-react-app)
5353

5454
## Architecture Overview

docs/docs/guides/feedback/index.md

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
sidebar_position: 15
3+
sidebar_label: '🗣️ Feedback'
4+
---
5+
6+
# Web3.js Developer Feedback
7+
8+
We highly value your feedback to continually improve our documentation and the web3.js library. Whether you have suggestions for improvement, requests for additional features, or simply want to let us know if the documentation has been helpful, please use the form linked below to provide your feedback.
9+
10+
## How to provide feedback
11+
12+
Please take a moment to fill out our [Web3.js User Feedback Form](https://forms.gle/7cWt1hPU43ayS53V9) to share your thoughts.
13+
14+
## What we will do with your feedback
15+
16+
We review all submissions regularly and use them to improve our documentation, address any gaps or issues, and ensure that our documentation and resources meets your needs effectively.
17+
18+
Thank you for taking the time to help us improve!
19+
20+
## Urgent questions or concerns
21+
22+
Please reach out to us:
23+
24+
[💬 Discord: `#web3js-general` channel](https://discord.gg/f5QhHUswtr)
25+
26+
[🐦 Twitter: `@web3_js`](https://twitter.com/web3_js)
27+
28+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
label: '⛑️ Hardhat Tutorial'
2+
collapsible: true
3+
collapsed: true
4+
link: null
5+
position: 2
Loading
Loading
Loading
+304
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
---
2+
sidebar_position: 1
3+
sidebar_label: Web3.js v4 with Hardhat
4+
---
5+
6+
# Using Web3 With Hardhat
7+
8+
## Introduction
9+
Following the recent compatibility update of Hardhat plugin [hardhat-web3-v4](https://hardhat.org/hardhat-runner/plugins/nomicfoundation-hardhat-web3-v4), `Web3.Js` is now available to use as plugin in Hardhat.
10+
11+
This tutorial will guide you through using Web3js as a plugin to interact with the Blockchain.
12+
13+
## Pre-requisite
14+
This tutorial assumes you have previous knowledge of writing Smart contracts, and are convenient working with Javascript/Typescript. You should have [NodeJS](https://nodejs.org/en) version greater than v16 installed.
15+
16+
:::note
17+
To install dependencies, we will use `NPM`.
18+
:::
19+
20+
## Steps
21+
- [Initiate a Hardhat project](#initiate-a-hardhat-project)
22+
- [Install required dependencies (including `hardhat-web3-v4`)](#install-required-dependencies-including-hardhat-web3-v4)
23+
- [Write the Smart Contract](#write-the-smart-contract)
24+
- [Compile and deploying the contract](#compile-test-and-deploy-the-contract)
25+
- [Testing and interacting with the contract](#testing-and-interacting-with-the-contract)
26+
27+
### Initiate a Hardhat project
28+
Create a new project folder and navigate into it.
29+
30+
```bash
31+
mkdir myproject
32+
```
33+
34+
```bash
35+
cd myproject
36+
```
37+
38+
Install and instantiate Hardhat in the current project.
39+
40+
```bash
41+
npm install hardhat
42+
```
43+
44+
```bash
45+
npx hardhat init
46+
```
47+
48+
![images](./asset/image_3.png)
49+
50+
### Install required dependencies (including `hardhat-web3-v4`)
51+
52+
Select `Typescript` and `Yes` for the rest of the options.
53+
You will be prompted to install the required dependencies. Reply `yes` to complete the installation.
54+
To include the `Hardhat-web3-v4` plugin, we will install it via `npm`.
55+
56+
```bash
57+
npm install --save-dev @nomicfoundation/hardhat-web3-v4 'web3@4'
58+
```
59+
60+
This will add Web3.Js to your project by including it in the 'node_modules' folder. To extend the Hardhat functionality with this plugin, we have to import the `web3-v4 plugin` in the Hardhat configuration file `hardhat.config.ts`. Import this at the top of the config file.
61+
62+
```ts
63+
import { HardhatUserConfig } from "hardhat/config";
64+
import "@nomicfoundation/hardhat-toolbox";
65+
import "@nomicfoundation/hardhat-web3-v4"; // <================
66+
67+
const config: HardhatUserConfig = {
68+
solidity: "0.8.19",
69+
};
70+
71+
export default config;
72+
73+
```
74+
75+
By default, `hardhat-toolbox` is added to the file. You will need to explicity invoke the plugin. This will modify the Hardhat Run-time Environment - HRE and to include both the Web3 class and an instantiated web3 object. With the latter, you get a modified ready-to-use web3 object can comes with an initialized local/Hardhat provider. The object will be available to use anywhere in the project such as testing and deployment files.
76+
77+
### Write the Smart Contract
78+
When you start a new project, Hardhat provides a sample `Lock` contracts. Please refer to the contract in `myproject/contracts/Lock.sol` file.
79+
80+
```ts
81+
// SPDX-License-Identifier: UNLICENSED
82+
pragma solidity ^0.8.9;
83+
84+
// Uncomment this line to use console.log
85+
// import "hardhat/console.sol";
86+
87+
contract Lock {
88+
uint public unlockTime;
89+
address payable public owner;
90+
91+
event Withdrawal(uint amount, uint when);
92+
93+
constructor(uint _unlockTime) payable {
94+
require(
95+
block.timestamp < _unlockTime,
96+
"Unlock time should be in the future"
97+
);
98+
99+
unlockTime = _unlockTime;
100+
owner = payable(msg.sender);
101+
}
102+
103+
function withdraw() public {
104+
// Uncomment this line, and the import of "hardhat/console.sol", to print a log in your terminal
105+
// console.log("Unlock time is %o and block timestamp is %o", unlockTime, block.timestamp);
106+
107+
require(block.timestamp >= unlockTime, "You can't withdraw yet");
108+
require(msg.sender == owner, "You aren't the owner");
109+
110+
emit Withdrawal(address(this).balance, block.timestamp);
111+
112+
owner.transfer(address(this).balance);
113+
}
114+
}
115+
116+
```
117+
118+
`Lock.sol` is a simple timeLock contract capable of accepting any amount of `Ether` at deployment while expecting one parameter that will be assigned to a state variable when deployed. The `withdraw` function allows only the address marked as `owner` to withdraw the total contract balance only if the 'unlockTime' is not in the future.
119+
120+
### Compile, test and deploy the contract
121+
- Compile and deploying the contract
122+
123+
```bash
124+
npx hardhat compile
125+
```
126+
Running the above command will generate a folder called `artifacts` containing the build information and the compiled contracts. From this directory, we will require the jasonInterface otherwise called the Application Binary Interface - ABI during testing and deployment.
127+
128+
![images](./asset/artifacts.png)
129+
130+
To deploy the contract, we will modify the `script/deploy.ts` file as shown below.
131+
132+
First, we import the initialized web3 object from hardhat. Next we get the artifacts.
133+
134+
```ts
135+
import { web3 } from "hardhat";
136+
import artifacts from "../artifacts/contracts/Lock.sol/Lock.json";
137+
138+
async function main() {
139+
140+
}
141+
142+
// We recommend this pattern to be able to use async/await everywhere
143+
// and properly handle errors.
144+
main().catch((error) => {
145+
console.error(error);
146+
process.exitCode = 1;
147+
});
148+
149+
```
150+
151+
Inside the main function, we prepare the deployment using a few of the web3.Js functionalities such as the `.utils` and `.eth` modules.
152+
153+
```ts
154+
async function main() {
155+
const currentTimestampInSeconds = Math.round(Date.now() / 1000);
156+
const unlockTime = currentTimestampInSeconds + 60;
157+
158+
const lockedAmount = web3.utils.toWei("0.001", 'ether');
159+
160+
const [deployer] = await web3.eth.getAccounts();
161+
const lockContract = new web3.eth.Contract(artifacts.abi);
162+
const rawContract = lockContract.deploy({
163+
data: artifacts.bytecode,
164+
arguments: [unlockTime],
165+
});
166+
167+
const lock = await rawContract.send({
168+
from: deployer,
169+
gasPrice: "10000000000",
170+
value: lockedAmount.toString()
171+
});
172+
173+
console.log(
174+
`Lock with ${web3.utils.toWei(
175+
lockedAmount,
176+
'ether'
177+
)}ETH and unlock timestamp ${unlockTime} deployed to ${lock.options.address}`
178+
);
179+
}
180+
181+
// We recommend this pattern to be able to use async/await everywhere
182+
// and properly handle errors.
183+
main().catch((error) => {
184+
console.error(error);
185+
process.exitCode = 1;
186+
});
187+
```
188+
Running the following command will deploy the `Lock` contract to a local Blockchain built into Hardhat. We use Web3.Js to talk to the Blockchain to broadcast our smart contract data to the network.
189+
190+
```bash
191+
npx hardhat run scripts/deploy.ts
192+
```
193+
194+
### Testing and interacting with the contract
195+
196+
In the previous steps, we compiled and deployed the contract to the local Blockchain network. It's time to test our contract ensuring it performs as expected. Since we used Web3.Js to talk to the Blockchain to broadcast and save our data, we will use same protocol to view and modify the data.
197+
198+
In the `myproject/test/Lock.ts` file, replace the content with the code below.
199+
200+
```ts
201+
import {
202+
time,
203+
loadFixture,
204+
} from "@nomicfoundation/hardhat-toolbox/network-helpers";
205+
import { expect } from "chai";
206+
import { web3 } from "hardhat";
207+
import artifacts from "../artifacts/contracts/Lock.sol/Lock.json";
208+
209+
describe("Lock", function () {
210+
async function deployOneYearLockFixture() {
211+
const ONE_YEAR_IN_SECS = 365 * 24 * 60 * 60;
212+
const ONE_GWEI = 1_000_000_000;
213+
214+
const lockedAmount = ONE_GWEI;
215+
const unlockTime = (await time.latest()) + ONE_YEAR_IN_SECS;
216+
217+
const lockContract = new web3.eth.Contract(artifacts.abi);
218+
lockContract.handleRevert = true;
219+
220+
const [deployer, otherAccount] = await web3.eth.getAccounts();
221+
const rawContract = lockContract.deploy({
222+
data: artifacts.bytecode,
223+
arguments: [unlockTime],
224+
});
225+
226+
// To know how much gas will be consumed, we can estimate it first.
227+
const estimateGas = await rawContract.estimateGas({
228+
from: deployer,
229+
value: lockedAmount.toString()
230+
});
231+
232+
const lock = await rawContract.send({
233+
from: deployer,
234+
gas: estimateGas.toString(),
235+
gasPrice: "10000000000",
236+
value: lockedAmount.toString()
237+
});
238+
239+
console.log("Lock contract deployed to: ", lock.options.address);
240+
return { lock, unlockTime, lockedAmount, deployer, otherAccount, rawContract };
241+
}
242+
243+
describe("Deployment", function () {
244+
it("Should set the right unlockTime", async function () {
245+
const { lock, unlockTime } = await loadFixture(deployOneYearLockFixture);
246+
const setTime = await lock.methods.unlockTime().call();
247+
console.log("SetTime", setTime);
248+
expect(setTime).to.equal(unlockTime);
249+
});
250+
251+
it("Should set the right deployer", async function () {
252+
const { lock, deployer } = await loadFixture(deployOneYearLockFixture);
253+
254+
expect(await lock.methods.owner().call()).to.equal(deployer);
255+
});
256+
257+
it("Should receive and store the funds to lock", async function () {
258+
const { lock, lockedAmount } = await loadFixture(
259+
deployOneYearLockFixture
260+
);
261+
const balance = await web3.eth.getBalance(String(lock.options.address));
262+
expect(balance).to.equal(lockedAmount);
263+
});
264+
265+
it("Shouldn't fail if the unlockTime has arrived and the deployer calls it", async function () {
266+
const { lock, unlockTime, deployer } = await loadFixture(
267+
deployOneYearLockFixture
268+
);
269+
270+
await time.increaseTo(unlockTime);
271+
await expect(lock.methods.withdraw().send({from: deployer})).not.to.be.reverted;
272+
});
273+
});
274+
});
275+
276+
```
277+
278+
in this file, we performed similar steps as in the deployment script to prepare and deploy the contract using the `ABI` and `bytecode` in `deployOneYearLockFixture()`. To read the `owner` data from the Blockchain, we used an instance of the deployed contract i.e `lock.methods.owner().call().`Invoking `.call()` does not change the state of the blockchain hence no wallet signature is required.
279+
280+
To change the status of the data we previously saved, we have to access the `method` container for the function (s) we desire and invoke the `.send` to broadcast our intention to the network `lock.methods.withdraw().send({from: deployer})`.
281+
282+
:::note
283+
When using `.send()`, you must explicitly provide the `sender` of the transaction in the `from` field (in the above example is the address of the `deployer` account).
284+
:::
285+
286+
287+
To run the test you can use the command
288+
```bash
289+
npx hardhat test test/Lock.ts
290+
```
291+
292+
And you'll get a similar result to this:
293+
```js
294+
/*
295+
Lock
296+
Deployment
297+
Lock contract deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3
298+
SetTime 1739193193n
299+
✔ Should set the right unlockTime (884ms)
300+
✔ Should set the right deployer (54ms)
301+
✔ Should receive and store the funds to lock
302+
✔ Shouldn't fail if the unlockTime has arrived and the deployer calls it
303+
*/
304+
```

0 commit comments

Comments
 (0)