hardhat框架使用与碰见的问题
日常开发
最主要的教程:超级权威的官网
hardhat框架命令
首先需要进入到hardhat安装目录,执行hardhat命令才会有效果,否则在一个新的目录下执行hardhat命令会需要重新创建一个hardhat项目并且需要重新install hardhat
初始化工程:
npm init --yes
生成package.json是管理依赖的包的
编译:
npx hardhat compile
hardhat多版本编译参考博客:多版本编译
hardhat.config.js配置信息:
module.exports = {
solidity: {
compilers: [ //可指定多个sol版本
{version: "0.4.26"},
{version: "0.5.12"},
{version: "0.6.12"}
]
},
networks: {
localhost: {
url: "http://127.0.0.1:8545"
},
// ropsten: {
// url: `https://eth-ropsten.alchemyapi.io/v2/${ALCHEMY_API_KEY}`,
// accounts: [`0x${ROPSTEN_PRIVATE_KEY}`]
// },
}
};
测试(本地起的链测试)
npx hardhat test
使用ganache测试
npx hardhat --network localhost test
终端:
ganache端设置:
合约部署本地网络:
npx hardhat run --network localhost scripts/deploy.js
合约部署上主网/测试网
npx hardhat run scripts/deploy.js --network ropsten
配置network的url地址时需要用到
链网节点连接申请:链网节点
hardhat用来fork主网操作:fork主网操作
注意全部把链接拷贝过来,注意测试网络名称之类的
部署完成:
使用另一个脚本进行测试
npx hardhat test scripts/action.js
从测试出发
参考:hardhat教程
参考二:教程二
hardhat测试用例说明:hardhat测试用例说明
部署远程网络命令:
npx hardhat run scripts/deploy.js --network rinkeby
在远端链上测试合约(声明网络即可,同远程网络部署)
npx hardhat test --network rinkeby
但是这里有个缺点,就是每次测试都需要在链上部署一次,非常浪费资源,这边通过fixtures解决(遗憾的是只能在hardhat本地网络使用)
fixtures实现合约一次部署,供测试用例多次使用
编写不同测试用例执行命令:
npx hardhat test ./test/test.js
chai断言库书写案例:chai断言库
事务型断言:
await expect(hardhatToken.connect(owner).transfer(addr2.address, 1000000000000)).to.be.revertedWith("Not enough tokens");
对应测试sol的代码:
require(balances[msg.sender] >= amount, "Not enough tokens");
测试时可能出现插件测试结果与区块转账记录不一致的情况,这时排查是交易时区块确认需要一定时间,但测试例子并没有等区块确认就直接返回了
// transfer test
const transfer = await hardhatToken.connect(owner).transfer(addr2.address, 988); // 返回了一个promise,还需要一个确认
await transfer.wait(); // 等待区块确认再执行下面的程序
参考博客:等待区块更新完成
部署时注意:
总结:
上面进入alchemy,infura获取api以及url的方式其实就是找到一个节点提供者,对应的url就是一个以太坊的一个节点,我们通过这个节点来向其他所有节点广播交易等操作。
hardhat部署上测试币安测试链
博客问题参考:https://ethereum.stackexchange.com/questions/97443/is-there-an-infura-equivalent-for-bsc
提供bsc网络节点网址:https://www.quicknode.com/endpoints/53525
在hardhat.config.js中配置币安链的连接节点:
bsc: {
url: `https://damp-holy-wave.bsc-testnet.discover.quiknode.pro/fa7c063hjhj30ajkj7494edjkjkj15f3fe4df05/`,
accounts: [GOERLI_PRIVATE_KEY,GOERLI_PRIVATE_KEY_2,GOERLI_PRIVATE_KEY_3]
}
这里的url是来源于节点提供网址
部署命令:
npx hardhat run scripts/deploy.js --network bsc
导入多个私钥,就可以使用到测试网上的多个用户了,
在测试案例中声明
这里面的owner,addr1,addr2就是按照私钥声明顺序配置的
const [owner,addr1,addr2] = await ethers.getSigners(); // 以太坊账户的对象
hardhat.config.js中配置:
/** @type import('hardhat/config').HardhatUserConfig */
require("@nomicfoundation/hardhat-toolbox");
require("@nomiclabs/hardhat-etherscan");
require("hardhat-abi-exporter");
const ALCHEMY_API_KEY = "lG8UXmscIphdsdsfsdsdsaNt0zzOYZXfgfgYQk3Zj6AKOW7";
const GOERLI_PRIVATE_KEY = "a7e49f98cc8906c3d7c0135b36cc5sdsd740dd1bcc90482fe6fe8e1fe88ecd52a0dsds45";
const GOERLI_PRIVATE_KEY_2 = "8633e0c08eb2f687431b34914029c39d05fesdsdsdsdjska155ea137fcd139db8b1374e7292";
const GOERLI_PRIVATE_KEY_3 = "bbc2885d17ff5da3b7350dsdsdc7937d89cf1dfd33995sdsde109c6d80b20d8d07bcf2aeac1";
module.exports = {
solidity: "0.8.9",
networks: {
rinkeby: {
url: `https://eth-rinkeby.alchemyapi.io/v2/${ALCHEMY_API_KEY}`,
accounts: [GOERLI_PRIVATE_KEY,GOERLI_PRIVATE_KEY_2,GOERLI_PRIVATE_KEY_3]
}
},
abiExporter: {
path: './abi',
runOnCompile: true,
clear: true,
flat: true,
spacing: 2,
pretty: false,
}
};
使用不同账户作为调用方进行测试:
编译部署时常见问题
- 编译时地址格式检查错误
- Remix传参错误,这里面地址需要加引号
- Remix部署时报编译文件数据过大
- hardhat编译时合约依赖库找不到问题
问题原因:https://hardhat.org/hardhat-runner/plugins/nomiclabs-hardhat-ethers#library-linking
参考解决博客:https://stackoverflow.com/questions/71389974/how-can-i-link-library-and-contract-in-one-file
代码:
// 先部署依赖库
const Lib = await ethers.getContractFactory("IterableMapping");
const lib = await Lib.deploy();
await lib.deployed();
// 部署合约时声明,注意libraries下时依赖库名即是IterableMapping,后面跟着依赖库部署后的地址
const bobyToken = await ethers.getContractFactory("BABYTOKEN",{
libraries: {
IterableMapping: lib.address,
}
}); // 单独部署一个合约
const bobytoken = await bobyToken.deploy("good good study", "GGSY", 100000000, ["0x9Ac64Cc6e4415144C45kjk5BD8E4837Fea55603e5c3",addr1.address,deployer.address],1,deployer.address,deployer.address);
- 编译时传递参数错误
原因:
// 正确示范
const bobytoken = await bobyToken.deploy("good good study", "GGSY", 100000000, ["0x9Ac64Cc6e4415144Chjh455BD8E4837Fea55603e5c3",addr1.address,deployer.address],1,deployer.address,deployer.address);
// 错误示范
const bobytoken = await bobyToken.deploy("good good study", "GGSY", 100000000, [0x9Ac64Cc6e4415144C455BD8E4837ghFea55603e5c3,addr1.address,deployer.address],1,deployer.address,deployer.address);
- 合约编译超出最大限制
解决:
设置编译时自动优化机制:
参考博客:https://forum.openzeppelin.com/t/governance-providererror-max-code-size-exceeded/25963/4
hardhat.config.js配置文件代码:
compilers: [
{
version: "0.8.9",
settings: {
optimizer: {
enabled: true,
runs: 200,
},
},
},
{
version: "0.4.24",
settings: {
optimizer: {
enabled: true,
runs: 200,
},
},
},
],
- 找不到配置网络(原来都好好的)
参考官方配置信息:官方配置
官方标准配置信息参考:
// 标准配置信息
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
}
}