ethereum-waffle v4.0.10
Library for writing and testing smart contracts.
Sweeter and simpler than truffle.
Works with ethers-js. Tastes best with ES6.
Philosophy
- Simpler: minimalistic, a couple of helpers, matchers and tasks rather than a framework, few dependencies.
- Sweeter: Nice syntax, fast, easy to extend.
Versions and ethers compatibility
- Use version 0.2.3+ with ethers 3.*
- Use version 1.0.0+ with ethers 4.*
Install:
To start using with npm, type:
npm i ethereum-waffle
or with Yarn:
yarn add ethereum-waffle
Step by step guide
Example contract
Below is example contract written in Solidity. Place it in contracts
directory of your project:
pragma solidity ^0.5.1;
import "../BasicToken.sol";
contract BasicTokenMock is BasicToken {
constructor(address initialAccount, uint256 initialBalance) public {
balances[initialAccount] = initialBalance;
totalSupply_ = initialBalance;
}
}
Example test
Belows is example test written for the contract above written with Waffle. Place it in test
directory of your project:
import chai from 'chai';
import {createMockProvider, deployContract, getWallets, solidity} from 'ethereum-waffle';
import BasicTokenMock from './build/BasicTokenMock';
chai.use(solidity);
const {expect} = chai;
describe('Example', () => {
let provider;
let token;
let wallet;
let walletTo;
beforeEach(async () => {
provider = createMockProvider();
[wallet, walletTo] = await getWallets(provider);
token = await deployContract(wallet, BasicTokenMock, [wallet.address, 1000]);
});
it('Assigns initial balance', async () => {
expect(await token.balanceOf(wallet.address)).to.eq(1000);
});
it('Transfer adds amount to destination account', async () => {
await token.transfer(walletTo.address, 7);
expect(await token.balanceOf(wallet.address)).to.eq(993);
expect(await token.balanceOf(walletTo.address)).to.eq(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 from empty account', async () => {
const tokenFromOtherWallet = contractWithWallet(token, walletTo);
await expect(tokenFromOtherWallet.transfer(wallet.address, 1))
.to.be.revertedWith('Not enough balance on sender account');
});
});
Compile
To compile contracts simply type:
npx waffle
To compile using custom configuration file:
npx waffle config.json
Example configuration file looks like this:
{
"sourcesPath": "./custom_contracts",
"targetPath": "./custom_build",
"npmPath": "./custom_node_modules"
}
Run tests
To run test type in the console:
mocha
Adding a task
For convince, you can add a task to your package.json
. In the sections scripts
, add following line:
"test": "waffle && test"
Now you can build and test your contracts with one command:
npm test
Features walkthrough
Import contracts from npms
Import solidity files from solidity files form npm modules that you added to your project, e.g:
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
Create a mock provider
Create a mock provider (no need to run any tests!) and test your contracts against it, e.g.:
provider = createMockProvider();
Get example wallets
Get wallets you can use to sign transactions:
[wallet, walletTo] = await getWallets(provider);
Deploy contract
Deploy a contract:
token = await deployContract(wallet, BasicTokenMock, [wallet.address, 1000]);
Link a library:
myLibrary = await deployContract(wallet, MyLibrary, []);
link(LibraryConsumer, 'path/to/file:MyLibrary.sol:MyLibrary', myLibrary.address);
libraryConsumer = await deployContract(wallet, LibraryConsumer, []);
Chai matchers
A set of sweet chai matchers, makes your test easy to write and read. Below couple of examples.
- Testing big numbers:
expect(await token.balanceOf(wallet.address)).to.eq(993);
Available matchers for BigNumbers are: equal
, eq
, above
, below
, least
, most
.
- Testing what events where emitted with what arguments:
await expect(token.transfer(walletTo.address, 7))
.to.emit(token, 'Transfer')
.withArgs(wallet.address, walletTo.address, 7);
- Testing if transaction was reverted:
await expect(token.transfer(walletTo.address, 1007)).to.be.reverted;
- Testing if transaction was reverted with certain message:
await expect(token.transfer(walletTo.address, 1007)).to.be.revertedWith('Insufficient funds');
- Testing if string is a proper address:
expect('0x28FAA621c3348823D6c6548981a19716bcDc740e').to.be.properAddress;
- Testing if string is a proper secret:
expect('0x706618637b8ca922f6290ce1ecd4c31247e9ab75cf0530a0ac95c0332173d7c5').to.be.properPrivateKey;
- Testing if string is a proper hex value of given length:
expect('0x70').to.be.properHex(2);
- Testing whether the transaction changes balance
await expect(() => myContract.transferWei(receiverWallet.address, 2)).to.changeBalance(receiverWallet, 2);
Note: transaction call should be passed to the expect as a callback (we need to check the balance before the call). The matcher can accept numbers, strings and BigNumbers as a balance change, while the address should be specified as a wallet.
changeBalance calls should not be chained. If you need to chain it, you probably want to use changeBalances matcher.
- Testing whether the transaction changes balance for multiple accounts
await expect(() => myContract.transferWei(receiverWallet.address, 2)).to.changeBalances([senderWallet, receiverWallet], [-2, 2]);
Fast complication
By default, Waffle uses solcjs. Solcjs is solidity complier cross-complied to javascript. It is slow, but easy to install. As an alternative, you can use the original Solidity compiler, which is faster, but requires more complex installation procedure, which is different for each operating system.
You can find installation instructions here.
Once installed you can use the following command for faster complication:
npx waffle --fast-compile
That should speed up complication time by a factor of x10.
Roadmap
- New matcher: changeBalance (see #9)
- Faster testing with parallelization
- Faster compilation with incremental compilation
- Documentation
- Debugging
6 months ago
6 months ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago