HardHat为开发者提供了许多合约开发的便捷功能,包括合约的编译、部署、验证、调试等方面。相对于使用其它工具,使用HardHat进行智能合约开发,可以:
方便的启动内置模拟节点;
使用内置打印接口在solidity代码内打印调试日志(console.log)
在合约报错查看call-stack,和详细报错原因
fork现有网络和状态来启动模拟节点
可以使用npm install将hardhat工具嵌入到任意现有的solidity工程代码目录内,或者创建全新的工程代码,使用如下代码在空目录中创建全新的solidity合约开发目录框架:
$ yarn add -D hardhat
$ yarn hardhat init
初始化完成后,目录结构如下:
.
├── README.md
├── contracts
│ └── Lock.sol
├── hardhat.config.js
├── package.json
├── scripts
│ └── deploy.js
├── test
│ └── Lock.js
└── yarn.lock
contracts目录放置solidity合约代码,scripts目录放置部署脚本test目录放置测试脚本。
使用Fork功能可以基于现有区块链网络RPC创建一个模拟的开发节点。这里的RPC推荐使用Alchemy提供的节点服务。
例如使用下面代码fork一个ethereum的主网开发环境:
(暂时不支持Wanchain,因为不识别transaction type: 255)
$ yarn hardhat node --fork https://eth-mainnet.g.alchemy.com/v2/<YouAlchemyApiKey>
也可在后方加入 --fork-block-number 14390000 参数来指定基于某一个块的状态来进行fork。
fork成功后,它会自动注入20个包含10000ETH的开发账号。同时包含以太坊的所有合约以及地址状态信息。
fork后的默认的RPC是: http://localhost:8545
chainId会发生变化,可以在添加到MetaMask的时候看到新chainId。(我本地当前是31337)
将fork节点添加到MetaMask网络,并将生成的测试私钥导入MetaMask钱包中,方便下一步开发使用。
为方便代码部署和调试,这里使用remix绑定本地文件目录功能,绑定刚刚建好的hardhat目录。使用如下指令绑定当前目录到remix:(remixd需要使用npm全局安装)
$ remixd -s .
在浏览器中打开:
在workspace位置选择localhost,即可连接到本地绑定目录,并看到我们的实例代码文件。

可以看到Lock.sol中的示例代码。我们在其中加入两行console.log日志打印,并在编译窗口选择合适的solidity版本进行编译。

在合约部署页面,选择使用MetaMask部署。

输入错误的构造函数参数时,可以在控制台的fork节点日志中看到错误提示信息:

输入正确的构造函数部署合约,可以在控制台中看到在合约代码中console.log输出的日志信息:

编译合约代码可以使用如下指令:
$ yarn hardhat compile
使用本地fork节点部署合约:
yarn hardhat run --network localhost scripts/deploy.js
这里的deploy.js是hardhat自带的实例代码,可根据自己需要任意修改。在fork节点的控制台窗口中可以看到部署成功的合约地址日志信息。
仿照示例代码编写一个withdraw.js,并使用如下指令执行:
const hre = require("hardhat");
async function main() {
const Lock = await hre.ethers.getContractFactory("Lock");
const lock = await Lock.attach("0xcbbe2a5c3a22be749d5ddf24e9534f98951983e2")
const tx = await lock.withdraw();
console.log(tx);
}
// 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;
});
yarn hardhat run --network localhost scripts/withdraw.js
如果执行成功,可以看到执行结果输出,如果执行失败,可以看到失败的具体原因显示。如果有多层级的函数调用,在失败时,可以看到call-stack调用堆栈,方便定位问题所在位置。(注意:调用堆栈功能在remix中不可用)

通过修改hardhat.config.js可以对编译参数进行详细配置,包括但不限于网络信息、solidity版本与优化信息、部署账户信息等。
module.exports = {
defaultNetwork: "rinkeby",
networks: {
hardhat: {
},
rinkeby: {
url: "https://eth-rinkeby.alchemyapi.io/v2/123abc123abc123abc123abc123abcde",
accounts: [privateKey1, privateKey2, ...]
}
},
solidity: {
version: "0.5.15",
settings: {
optimizer: {
enabled: true,
runs: 200
}
}
},
paths: {
sources: "./contracts",
tests: "./test",
cache: "./cache",
artifacts: "./artifacts"
},
mocha: {
timeout: 40000
}
}
https://hardhat.org/hardhat-network/docs/overview
https://hardhat.org/hardhat-runner/docs/getting-started#overview
