今天在Hardhat测试合约,发现"unresolved libraries"问题,如图(1)所示:
出现这种现象的原因是:若library是自定义的库文件,在部署合约时,需要手动link到合约里。
解决方法:先部署库合约,得到库合约地址,将这个地址放到业务合约的libraries列表即可。这个库合约必须要有public函数可供外部调用,不能使用函数全为internal的库合约(因为internal的库合约无法导出)。
// 1) 部署LibMath库合约
libFactory = await ethers.getContractFactory("LibMath");
libObj = await libFactory.deploy()
// 2)部署CountOne合约
// 将CountOne所引用的库合约,全部放到libraries列表里
contractFactory = await ethers.getContractFactory("CountOne",{
libraries: {
LibMath: libObj.address
}
});
这里以CountOne.sol引用LibMath.sol库文件为例,进行说明。
1、创建LinkLib工程
1.1 创建文件夹
## 1)创建工程目录
mkdir LinkLib
cd LinkLib
npm init -y
## 2)创建合约文件夹、测试文件夹
mkdir contracts test
1.2 设置依赖包
在package.json里添加dependencies、devDependencies这2个字段:
{
"name": "LinkLib",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@nomiclabs/hardhat-ethers": "^2.0.2",
"@nomiclabs/hardhat-waffle": "^2.0.1",
"chai": "^4.3.4",
"ethereum-waffle": "^3.4.0",
"ethereumjs-abi": "^0.6.8",
"ethers": "^5.4.7",
"ts-node": "^10.0.0",
"typescript": "^4.3.5",
"hardhat": "^2.4.1"
}
}
然后,安装这些依赖包
npm install
1.3 设置hardhat
hardhat.config.js是hardhat的配置文件,其设置如下:
//hardhat.config.js
require("@nomiclabs/hardhat-waffle");
module.exports = {
solidity: {
compilers: [
{version: "0.5.16"},
{version: "0.5.12"},
{version: "0.6.6"},
]
}
};
1.4 创建业务合约
在contracts目录里,创建一个业务合约CountOne.sol,用于设置count的增减。
// CountOne.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import "./LibMath.sol";
contract CountOne {
using LibMath for uint256;
uint public count;
address public owner;
constructor() public {
count = 0;
owner = msg.sender;
}
function getCount() public view returns(uint) {
return count;
}
function getOwner() public view returns(address) {
return owner;
}
function increaseCount() public {
count = count.add(1);
}
function decreaseCount() public {
count = count.sub(1);
}
function clearCount() public onlyOwner {
count = 0;
}
modifier onlyOwner() {
require(owner == msg.sender,"info: caller is not owner");
_;
}
}
1.4 创建库合约
在contracts目录里,创建减加乘除的库合约: LibMath.sol,库合约里必须要有public公开的函数接口,否则无法链接到业务合约。
//LibMath.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
library LibMath {
function add(uint256 a, uint256 b) public pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) public pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
function mul(uint256 a, uint256 b) public pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) public pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b > 0, errorMessage);
uint256 c = a / b;
return c;
}
function mod(uint256 a, uint256 b) public pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
1.6 工程目录结构
LinkLib工程的目录结构如下:
2 编写测试脚本
在LinkLib/test目录里,创建用于测试CountOne.sol合约的脚本: CountOne_test.js
//CountOne_test.js
const { expect } = require("chai")
const { ethers } = require("hardhat")
const { utils } = require("ethers");
describe("CountOne Test", function() {
let contractFactory;
let contractObj;
let libFactory;
let libObj;
let owner,addr1,addr2,addr3,addrs;
before(async function() {
// 1) 部署LibMath库合约
libFactory = await ethers.getContractFactory("LibMath");
libObj = await libFactory.deploy();
console.log("libObj addr",libObj.address);
[owner,addr1,addr2,addr3,...addrs] = await ethers.getSigners();
// 2)部署CountOne合约
// 将CountOne所引用的库合约,全部放到libraries列表里
contractFactory = await ethers.getContractFactory("CountOne",{
libraries: {
LibMath: libObj.address
}
});
contractObj = await contractFactory.deploy();
});
describe("Deployment", function() {
it("Check owner", async ()=> {
expect(owner.address).to.equal(await contractObj.getOwner());
});
it("Check increaseCount() func", async ()=> {
await contractObj.increaseCount();
let num = await contractObj.getCount()
expect(num).to.equal(1);
})
it("Check decreaseCount() func", async ()=> {
await contractObj.decreaseCount();
let num = await contractObj.getCount()
expect(num).to.equal(0);
})
});
})
3、进行测试
在命令行窗口,输入如下命令:
npx hardhat test test\CountOne_test.js
效果如下: