安装 先保证本地安装好了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.js为solidity: "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 (); } 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 Web3w3 = 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