hardhat简介

安装

先保证本地安装好了npm,运行npm install --save-dev hardhat。安装成功之后,运行npx hardhat。如果出现类似如下的界面就表示安装成功:

1
2
3
4
5
6
7
8
9
10
$ npx hardhat
888 888 888 888 888
888 888 888 888 888
888 888 888 888 888
8888888888 8888b. 888d888 .d88888 88888b. 8888b. 888888
888 888 "88b 888P" d88" 888 888 "88b "88b 888
888 888 .d888888 888 888 888 888 888 .d888888 888
888 888 888 888 888 Y88b 888 888 888 888 888 Y88b.
888 888 "Y888888 888 "Y88888 888 888 "Y888888 "Y888

hardhat目录结构

在运行完毕之后,我们可以得到一个这样的demo合约。整个文件的目录结构如下所示:

1
artifacts  cache  contracts  hardhat.config.js  node_modules  package.json  package-lock.json  README.md  scripts  test
  • contracts,存放合约文件
  • hardhat.config.js,配置文件。编译的solidity版本,部署的网络等等都是在此文件中配置
  • test,存放测试脚本,可用作单元测试;
  • scripts,一般是用作存放部署脚本;

编写合约

按照基础目录结构,在contract中放入自定义合约文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.8.15;

contract Random {

bool public solved = false;

function _getRandomNumber() internal pure returns (uint256) { // chosen by fair dice roll.
return 4; // guaranteed to be random.
}

function solve(uint256 guess) public {
require(guess == _getRandomNumber());
solved = true;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.8.15;

import "./Random.sol";

contract Setup {

Random public random;

constructor() {
random = new Random();
}

function isSolved() public view returns (bool) {
return random.solved();
}
}

由于sol的合约代码全部使用0.8.15编写,修改hardhat.config.jssolidity: "0.8.15"
合约编写完毕之后,使用npx hardhat compile。如果程序成功输出Compiled 2 Solidity files successfully,说明没有问题。

为了验证我们的合约可以成功编译和部署,可以在test目录下,创建一个random.js,基础内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const { expect } = require("chai");

describe("Token contract", function () {
it("Deployment should assign the total supply of tokens to the owner", async function () {
const [owner] = await ethers.getSigners();

const Setup = await ethers.getContractFactory("Setup");

const setup = await Setup.deploy();

const random_var = await setup.random();

console.log(setup.address);
console.log(random_var);
console.log(random_var.address)
});
});

使用npx hardhat test运行,如果结果成功输入如下的内容,那就说明没有问题;
如果需要本地调用,就需要部署合约。部署合约需要创建一个deploy.js文件,基本代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const hre = require("hardhat");

async function main() {
const currentTimestampInSeconds = Math.round(Date.now() / 1000);
const ONE_YEAR_IN_SECS = 365 * 24 * 60 * 60;
const unlockTime = currentTimestampInSeconds + ONE_YEAR_IN_SECS;


const Setup = await hre.ethers.getContractFactory("Setup");
const setup = await Setup.deploy();

await setup.deployed();

}

// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});

要在运行任何任务时指定 Hardhat 连接到特定的以太坊网络,可以使用–network参数。像这样:

1
npx hardhat run scripts/deploy.js --network <network-name>

如果没有带network参数,相当于是一次性运行。当Hardhat完成运行时,部署实际上会丢失。

如果需要在本地部署:首先需要启动harhat服务:npx hardhat node(窗口1)。然后在另一个窗口运行npx hardhat run scripts/deploy.js --network localhost(窗口2)。如果在窗口1出现如下的内容,就表示在本地部署成功:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
eth_chainId
eth_accounts
eth_blockNumber
eth_chainId (2)
eth_estimateGas
eth_getBlockByNumber
eth_feeHistory
eth_sendTransaction
Contract deployment: Setup
Contract address: 0x5fbdb2315678afecb367f032d93f642f64180aa3
Transaction: 0x545c30efaadabe5cd58ad16cb8b38dd6164a738b7f69b84c2e5dbf3ebfea944e
From: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
Value: 0 ETH
Gas used: 342117 of 342117
Block #1: 0x06fbb21123ead40730db027016fbe034cacdd76ed1c2f43cf6a267badc93def4

eth_chainId
eth_getTransactionByHash
eth_chainId
eth_getTransactionReceipt

尝试使用python的方式测试本地rpc是否运行正常:

1
2
3
from web3 import Web3
w3 = Web3(Web3.HTTPProvider('http://127.0.0.1:8545'))
print(w3.isConnected())

如果返回的是True,就说明本地部署成功;

当使用Python和web3实际调用相关代码时,默认情况下会使用到第一个账户,所以很多时候我们并没有关心我们调用的方法所消耗的gas。

1
2
3
random_contract = w3.eth.contract(address=Web3.toChecksumAddress(random_address),
abi=json.loads(random_abi))
random_contract.functions.solve(4).transact()

如上代码所示,当我们使用python web3调用random合约的solve()方法时,使用的账户就是0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266(这个账户是hardhat默认的i的一个账户,创建setup合约也是用的这个账户),消耗的gas是43835。但是我们在实际写代码时,并没有考虑这些。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
  Contract deployment: Setup
Contract address: 0x5fbdb2315678afecb367f032d93f642f64180aa3
Transaction: 0x545c30efaadabe5cd58ad16cb8b38dd6164a738b7f69b84c2e5dbf3ebfea944e
From: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
Value: 0 ETH
Gas used: 342117 of 342117
Block #1: 0x06fbb21123ead40730db027016fbe034cacdd76ed1c2f43cf6a267badc93def4

eth_chainId
eth_getTransactionByHash
eth_chainId
eth_getTransactionReceipt
web3_clientVersion
eth_chainId
eth_accounts
eth_call
Contract call: Setup#random
From: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
To: 0x5fbdb2315678afecb367f032d93f642f64180aa3

eth_getBlockByNumber
eth_chainId (2)
eth_estimateGas
eth_blockNumber
eth_getBlockByNumber
eth_sendTransaction
Contract call: Random#solve
Transaction: 0xf6f852069139f5f16e4fd0c7161e75485a53fd3bd10101dea546b9752d183710
From: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
To: 0xa16e02e87b7454126e5e10d957a927a7f5b5d2be
Value: 0 ETH
Gas used: 43835 of 143835
Block #2: 0x38e365e1ba9fbb94ab5486f0a5822f95df82a91b7d21408cb13454f7efb8eb71

参考

https://segmentfault.com/a/1190000041504179#item-4

https://hardhat.org/hardhat-runner/docs/guides/deploying

文章作者: Oooverflow
文章链接: https://www.oooverflow.com/2022/08/30/hardhat-guides/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Oooverflow