- Hardhat: 基于 2.19 版本的
- contract.target 是合约地址。
- ethers: ^6.4.0
ethers.parseEther('1')
console
import "hardhat/console.sol";
console.log(amount);
test
import { time, loadFixture } from "@nomicfoundation/hardhat-network-helpers";
// import { anyValue } from '@nomicfoundation/hardhat-chai-matchers/withArgs'
import { expect } from "chai";
import { ethers } from "hardhat";
import { BigNumber } from "ethers";
获取地址
const address = await ethers.getSigners(); // address 是一个地址集合
// 地址展开
const [owner, user1, user2, user3, user4, user5, user6, user7, user8, user9, user10] = await ethers.getSigners();
如果需要多账号多金额
hardhat: {
allowUnlimitedContractSize: true,
chainId: 22,
accounts: {
count: 100,
accountsBalance: "88880000000000000000000000",
},
},
部署合约
const Lock = await ethers.getContractFactory("Lock");
const lock = await Lock.deploy(unlockTime, { value: lockedAmount });
时间穿梭
await time.increaseTo(unlockTime); // 穿梭时间
await time.advanceBlockTo(20); // 穿梭区块
异常判断
// 基本
expect(await lock.owner()).to.equal(owner.address); // 相等
expect(await lock.xxx()).to.be.not.equal(10); // 不相等
expect(await lock.xxx()).to.be.above(5); // 大于
expect(await lock.xxx()).to.be.least(5); // 大于等于
expect(await lock.xxx()).to.be.below(20); // 小于
expect(await lock.xxx()).to.be.most(20); // 小于等于
// reverted
await expect(contract.call()).to.be.reverted; // reverted
await expect(lock.withdraw()).not.to.be.reverted; // not reverted
// reverted 预期错误信息
await expect(contract.call()).to.be.revertedWith("Some revert message");
await expect(contract.call()).not.to.be.revertedWith("Another revert message");
// ------> owner 普通合约错误
await expect(xxx.connect(user4).setClaimable(false)).to.be.revertedWith('Ownable: caller is not the owner')
// 自定义错误
await expect(contract.call()).to.be.revertedWithCustomError(contract, "SomeCustomError");
await expect(contract.call()).to.be.revertedWithCustomError(contract, "SomeCustomError").withArgs(anyValue, "some error data string");
// ------> owner 可升级合约错误
await expect(xxx.connect(user4).setClaimable(false)).to.be.revertedWithCustomError(xxx, "OwnableUnauthorizedAccount").withArgs(user4.address);
// 事件触发
await expect(lock.withdraw()).to.emit(lock, "Withdrawal").withArgs(lockedAmount, anyValue);
// ETH余额变化
await expect(lock.withdraw()).to.changeEtherBalances([owner, lock], [lockedAmount, -lockedAmount]);
await expect(() => sender.sendTransaction({ to: someAddress, value: 200 })).to.changeEtherBalance(sender, "-200");
await expect(token.transfer(account, 1)).to.changeTokenBalance(token, account, 1);
// 多个地址同时检查
await expect(() => sender.sendTransaction({ to: receiver, value: 200 })).to.changeEtherBalances([sender, receiver], [-200, 200]);
await expect(token.transferFrom(sender, receiver, 1)).to.changeTokenBalances(token, [sender, receiver], [-1, 1]);
一些库的接口实现判断
it('supportsInterface', async function () {
const { owner, admin, dev, treasury, user1, user2, user3, xxx } = await loadFixture(deployFixture)
// ERC165 0x01ffc9a7
// ERC721 0x80ac58cd
// ERC721Metadata 0x5b5e139f
// ERC721TokenReceiver 0x150b7a02
// ERC721Enumerable 0x780e9d63
// AccessControl 0x7965db0b
expect(await xxx.supportsInterface('0x01ffc9a7')).to.equal(true);
expect(await xxx.supportsInterface('0x80ac58cd')).to.equal(true);
expect(await xxx.supportsInterface('0x5b5e139f')).to.equal(true);
expect(await xxx.supportsInterface('0x150b7a02')).to.equal(false);
expect(await xxx.supportsInterface('0x780e9d63')).to.equal(false);
expect(await xxx.supportsInterface('0x7965db0b')).to.equal(false);
})
fallback 测试
it('🥷 should invoke the fallback()', async function () {
const { deployer, owner, user4, xxx } = await loadFixture(deployFixture);
await expect(user4.sendTransaction({
to: xxx.target,
data: "0xdf"
}))
.to.emit(xxx, "UnknownError").withArgs(user4.address, "0xdf");
})
Debug
ether.js
转账给其他地址
// 转账给其他地址
const [owner, user1, user2, user3, user4, user5, user6, user7, user8, user9, user10] = await ethers.getSigners();
await user10.sendTransaction({
to: user1.address,
value: ethers.utils.parseEther("1.0"), // Sends exactly 1.0 ether
});
const balance = await ethers.provider.getBalance(user1.address);
expect(balance).to.equal(ethers.parseEther('1'))
测试 library
使用 waffle 来进行。
- https://github.com/NomicFoundation/hardhat-waffle
- https://hardhat.org/hardhat-runner/plugins/nomiclabs-hardhat-waffle
更多参考资料
相关的命令
Command Line
- install :
npm i
- create
.env
file in project root path- mirror
.env.example
- mirror
- compile :
npm run compile
- if got
Error HH12
: run commandnpm install --save-dev hardhat
- test :
npm run test
- coverage :
npm run coverage
- view methods gas :
npm run gas
- deploy on hardhat temp network
npm run d
- deploy on localhost network
- Terminal 1:
npm run node
- Terminal 2:
npm run d:l
- Terminal 1:
- deploy on blockchain network
- ✅ Product:
npm run d:fbchain
- ✅ Product:
All scripts is in package.json
file.
Open in remixd web
npm install -g @remix-project/remixd
remixd
/npm run remixd
常见的命令
"scripts": {
"compile": "npx hardhat compile && node batch/abi.ts",
"docs": "npx hardhat dodoc",
"node": "npx hardhat node",
"test": "npx hardhat test",
"coverage": "npx hardhat coverage && npx http-server ./coverage/ -o",
"gas": "REPORT_GAS=true npx hardhat test",
"abi": "npx hardhat export-abi",
"d": "npx hardhat run scripts/deploy.ts",
"d:l": "npx hardhat run --network localhost scripts/deploy.js",
"d:test": "npx hardhat run scripts/deploy.ts --network bsc_test",
"d:bsc": "npx hardhat run scripts/deploy.ts --network bsc",
"up": "npx hardhat run scripts/upgrade.ts --network bsc_test",
"v:test": "npx hardhat verify --network bsc_test <CONTRACT_ADDRESS>",
"v:bsc": "npx hardhat verify --network bsc <CONTRACT_ADDRESS>",
"remixd": "open http://remix.ethereum.org/ && remixd -s ./ --remix-ide http://remix.ethereum.org/",
"lint": "solhint 'contracts/*.sol'",
"lint:fix": "solhint 'contracts/**/*.sol' --fix",
"format": "prettier --write .",
},