赞
踩
Waffle是什么呢?我们直接看其文档上的介绍:
Waffle is a library for writing and testing smart contracts. Sweeter, simpler and faster than Truffle. Works with ethers-js.
大致意思为,它是一个编写和测试(以太坊上)智能合约的库,比Truffle更加好用,简单和快速,它使用了ethers-js
。
注:(ethers-js
是一个非常棒的以太坊js框架,个人觉得甚至好于web3.js
)。
介绍完之后我们根据其官方文档进行初次使用。
yarn安装链接为:https://yarn.bootcss.com/docs/install/#mac-stable,注意选择相应的操作系统。
打开一个终端,运行下面的命令:
mkdir waffle_test
cd waffle_test/
yarn init
然后一路回车,会出现如下提示:
success Saved package.json
✨ Done in 25.49s.
这说明我们的yarn工程已经建立好了。我们接着运行code .
来使用VS Code打开该工程(如果没有code
命令就手动打开VS Code)。
在VS Code里我们可以看到本工程仅有一个package.json
,接下来我们一步一步充实该工程。
下面我们按照其官方文档介绍的流程进行操作:
ethereum-waffle
打开VS Code的终端菜单,新建一个终端,在其中运行:
yarn add --dev ethereum-waffle
yarn add @openzeppelin/contracts -D
可以看到,我们安装了openzeppelin
提供的一些标准模板合约。
在项目根目录下新建src
目录,并在src
目录下建立BasicToken.sol
,内容如下:
pragma solidity ^0.6.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
// Example class - a mock class using delivering from ERC20
contract BasicToken is ERC20 {
constructor(uint256 initialBalance) ERC20("Basic", "BSC") public {
_mint(msg.sender, initialBalance);
}
}
可以看到,这是一个简单的测试用的ERC20合约,在构造器里初始化了发行总量。
package.json
,添加如下内容。{
"scripts": {
"build": "waffle"
}
}
注意:官方文档提到,当waffle版本不同时,它的内容也不同。waffle 3.0.0以上(当前版本是3.2.0)就是这样设置;如果是2.5.0版本,则为:
{
"scripts": {
"build": "waffle waffle.json"
}
}
我们当前是3.0.0以上版本,所以不需要手动在后面加waffle.json
,默认值就是它。
waffle.json
在项目根目录下创建waffle.json
,内容为:
{
"compilerType": "solcjs",
"compilerVersion": "0.6.2",
"sourceDirectory": "./src",
"outputDirectory": "./build"
}
它定义了一些最基本的配置,很容易看明白。但是这里按照官方文档实际操作有些问题,我们接下来会讲。
运行yarn build
。
会提示获取不到0.6.2版本的编译器,怎么办呢?我们可以参考Uniswap
项目,修改上面的waffle.json
,将compilerVersion
的值改为:"./node_modules/solc"
,官方文档有介绍compilerVersion
的几种格式。
所以修改后的waffle.json
为:
{
"compilerType": "solcjs",
"compilerVersion": "./node_modules/solc",
"sourceDirectory": "./src",
"outputDirectory": "./build"
}
再次运行yarn build
,则会有Done in 5.93s.
类似的提示,代表我们合约已经编译好了。这时可以看到,项目根目录下多了build
目录,里面有多个json
文件,这就是编译后合约对应的json文件。
Waffle使用Mocha
和Chai
进行测试,所以必须先安装它们:
yarn add --dev mocha chai
安装完成之后,在项目根目录下新建test
目录,然后在该目录下新建BasicToken.test.ts
,内容如下:
import {expect, use} from 'chai'; import {Contract} from 'ethers'; import {deployContract, MockProvider, solidity} from 'ethereum-waffle'; import BasicToken from '../build/BasicToken.json'; use(solidity); describe('BasicToken', () => { const [wallet, walletTo] = new MockProvider().getWallets(); let token: Contract; beforeEach(async () => { token = await deployContract(wallet, BasicToken, [1000]); }); it('Assigns initial balance', async () => { expect(await token.balanceOf(wallet.address)).to.equal(1000); }); it('Transfer adds amount to destination account', async () => { await token.transfer(walletTo.address, 7); expect(await token.balanceOf(walletTo.address)).to.equal(7); }); it('Transfer emits event', async () => { await expect(token.transfer(walletTo.address, 7)) .to.emit(token, 'Transfer') .withArgs(wallet.address, walletTo.address, 7); }); it('Can not transfer above the amount', async () => { await expect(token.transfer(walletTo.address, 1007)).to.be.reverted; }); it('Can not transfer from empty account', async () => { const tokenFromOtherWallet = token.connect(walletTo); await expect(tokenFromOtherWallet.transfer(wallet.address, 1)) .to.be.reverted; }); it('Calls totalSupply on BasicToken contract', async () => { await token.totalSupply(); expect('totalSupply').to.be.calledOnContract(token); }); it('Calls balanceOf with sender address on BasicToken contract', async () => { await token.balanceOf(wallet.address); expect('balanceOf').to.be.calledOnContractWith(token, [wallet.address]); }); });
本测试文件由官方文档提供,具体测试内容很简单,有兴趣的读者可以自己看一下。这里因为主要是介绍waffle的使用,所以略过测试内容及测试文件的编写。
根据其官方文档,运行测试前我们需要更新package.json
,使之包括如下内容:
{
"scripts": {
"build": "waffle",
"test": "export NODE_ENV=test && mocha",
}
}
这里其实就是加上test
脚本的运行命令。
然后运行yarn test
。
然而,会报出Error: No test files found: "test"
,这是为什么呢?严格按照官方文档操作怎么就报错了呢,笔者在这里也坑了许久。多方查阅及和waffle
本身的示例对照之后发现,是少了一个Mocha
的配置文件。因为我们安装的是最新的Mocha
,所以这里需要修改一下package.json
,添加一个mocha
属性并设置,使之包含如下内容:
{
"mocha":{
"extension": ["ts"],
"spec": "./test/**/*.test.ts",
"require": "ts-node/register",
"timeout": 12000
},
}
然后再次运行yarn test
,会报错说找不到一些依赖包,这个我们下一步来解决。
注意:这里需要说明的是,mocha
配置文件的设置方法有好几种(查看mocha对应的官方文档)。Waffle在github仓库中的示例使用的方法不是在package
里设置,而是在test
目录下新建了一个mocha.opts
,其内容为:
-r ts-node/register/transpile-only
--timeout 50000
--no-warnings
test/**/*.test.{js,ts}
然而经过测试,当前mocha
的版本为8.2.1
(这个可以从package.json
中查看)时,它不会读取mocha.opts
,所以就算test
目录下有此文件,也仍然会出现Error: No test files found: "test"
的问题。
解决该问题的办法有两种:
mocha
的版本回退,比如设置为"^7.1.2"
,然后再运行yarn
来安装该版本的mocha
,这样就可以读取配置文件了。package.json
里(或者别处,参考mocha
文档)进行设置而不是使用test/mocha.opts
。接着刚才的操作,请确认是在package.json
里进行mocha
设置而不是使用mocha.opts
。
再次运行yarn test
会提示ERROR: Error: Cannot find module 'ts-node/register'
。这是一些依赖库未安装,我们来依次安装:
yarn add ts-node -D
yarn add typescript -D
yarn add @types/chai -D
yarn add @types/mocha -D
tsconfig.json
安装完成之后我们再次运行yarn test
。
然而,又又又报错了,这次提示为:error TS2732: Cannot find module '../build/BasicToken.json'
,意思为找不到目录下相应的json文件。这里通过比对其示例,发现少了一个tsconfig.json
配置文件。
我们把它加上去,在项目根目录下新建tsconfig.json
,内容如下(该内容直接复制的官方示例):
{ "compilerOptions": { "declaration": true, "esModuleInterop": true, "lib": [ "ES2018" ], "module": "CommonJS", "moduleResolution": "node", "outDir": "dist", "resolveJsonModule": true, "skipLibCheck": true, "strict": true, "target": "ES2018" } }
再次运行yarn test
,会有类似如下输出:
yarn run v1.22.5 $ export NODE_ENV=test && mocha BasicToken ✓ Assigns initial balance ✓ Transfer adds amount to destination account (120ms) ✓ Transfer emits event (97ms) ✓ Can not transfer above the amount ✓ Can not transfer from empty account ✓ Calls totalSupply on BasicToken contract ✓ Calls balanceOf with sender address on BasicToken contract 7 passing (2s) ✨ Done in 8.88s.
可以看到,我们的测试成功了。
package.json
这里放出完整package.json
,方便大家对照一下。
{ "name": "waffle_test", "version": "1.0.0", "main": "index.js", "license": "MIT", "devDependencies": { "@openzeppelin/contracts": "^3.2.0", "@types/chai": "^4.2.14", "@types/mocha": "^8.0.4", "chai": "^4.2.0", "ethereum-waffle": "^3.2.0", "mocha": "^8.2.1", "ts-node": "^9.0.0", "typescript": "^4.0.5" }, "mocha":{ "extension": ["ts"], "spec": "./test/**/*.test.ts", "require": "ts-node/register", "timeout": 12000 }, "scripts": { "build": "waffle", "test": "export NODE_ENV=test && mocha" } }
总结一下,Waffle
使用还是挺简单的,但对照其官方文档操作会出现一些坑,也花了一些时间来解决。主要是因为官方文档介绍的流程是有一定的前提条件的,不是从零开始详细介绍其操作过程。另外软件版本的更新也引起了一些问题。
欢迎大家留言指正错误或者提出改进意见。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。