Testing with Hardhat and Typechain
In this article, you’ll learn how to test smart contracts with Hardhat and Typechain.Objectives
By the end of this lesson, you should be able to:- Set up TypeChain to enable testing
- Write unit tests for smart contracts using Mocha, Chai, and the Hardhat Toolkit
- Set up multiple signers and call smart contract functions with different signers
Overview
Testing is an important aspect of software development and developing smart contracts is no different. In fact, you need to be more careful because smart contracts usually manage money and live in an adversarial environment, where anyone can see the code and interact with your smart contract. This means you can expect bad actors to try to exploit your smart contracts.Setup Typechain
In the previous guide, you created a new project using theinit
command that by default installs @nomicfoundation/hardhat-toolbox
. This package already contains Typechain, which is a plugin that generates static types for your smart contracts. This means you can interact with your contracts and get immediate feedback about the parameters received by a particular function and the functions of a smart contract.
The best way to see its true potential is to start writing tests.
After compiling the hardhat project in the previous lesson, a new folder called typechain-types
was created, which Typechain is already installed and running.
Writing your first unit test with Typechain
Hardhat includes a sample smart contract namedLock.sol
and a sample test inside the test folder named Lock.ts
.
In the following, you reuse this smart contract but rewrite the test using Typechain.
To remove the body of the Lock.ts
file:
typechain-types
, Lock
, and Lock__Factory
.
Typechain always creates two files per contract. The first one Lock
refers to the type and functions of a particular contract. Lock__Factory
is used to deploy the Lock contract or to create instances of a particular contract.
The Lock.sol
contract allows the creator to lock Ether until an unlock time has passed.
Notice the constructor has a payable keyword:
- The unlock time value
- The value locked during creation
- The owner address
- The withdraw function
Testing unlockTime
Next, you include test cases after the before
function.
The first test case should verify that the unlockTime
variable is correct.
Testing Ether balance
In order to get the balance of yourLock
contract, you simply call ethers.provider.getBalance
.
Create a new test case:
Then, run
npx hardhat test
and you should get:
Testing owner
Similar to the previous test cases, you can verify that the owner is correct.
Then, run
npx hardhat test
and you should get:
Testing withdraw
Testing withdrawal is more complex because you need to assert certain conditions, such as:- The owner cannot withdraw before the unlock time.
- Only the owner can withdraw.
- The withdraw function works as expected.
withdraw
reverts with a particular message:
the block.timestamp
by using the time helper:
You can then run
npx hardhat test
and you should get: