Debugging smart contracts using Hardhat
In this tutorial, you’ll learn how to debug your smart contracts using the built-in debugging capabilities of Hardhat.Objectives
By the end of this tutorial, you should be able to:- Use
console.logto write debugging logs - List common errors and their resolutions
- Determine if an error is a contract error or an error in the test
Overview
Debugging smart contracts can be a challenging task, especially when dealing with decentralized applications and blockchain technology. Hardhat provides powerful tools to simplify the debugging process. In this tutorial, you will explore the essential debugging features offered by Hardhat and learn how to effectively identify and resolve common errors in your smart contracts.Your first console.log
One of the key features of Hardhat is the ability to use console.log for writing debugging logs in your smart contracts. In order to use it, you must include hardhat/console.sol in the contract you wish to debug.
In the following contract Lock.sol for example, you include hardhat/console.sol by importing it and adding a few console.logs in the constructor with the text “Creating” and the Ether balance of the contract. This can help you not only with tracking that the contract was created successfully but also, more importantly, with the ability to include additional logs such as the balance of the contract after it was created:
test folder called Lock.test.ts with the following content:
before hook. Then, you can run:
value property.
A note about console.log
In the previous example, you used console.log to include some debugging logs. Be aware that the console.log version of Solidity is limited compared to the ones that are provided in other programming languages, where you can log almost anything.
Console.log can be called with up to four parameters of the following types:
- uint
- string
- bool
- address
console functions, such as:
- console.logInt(int i)
- console.logBytes(bytes memory b)
- console.logBytes1(bytes1 b)
- console.logBytes2(bytes2 b)
- …
- console.logBytes32(bytes32 b)
console.log. For further details, refer to the official console.log documentation.
Identifying common errors
While debugging your smart contracts, it’s crucial to be familiar with common errors that can arise during development. Recognizing these errors and knowing how to resolve them is an important skill. In our Base Learn series of tutorials, we cover a few compile-time errors in Error Triage. Other errors, such asreverts or index out of bounds errors can be unexpected during the runtime of the smart contract.
The following explores typical techniques to debug these types of errors.
Revert errors
When a transaction fails due to arequire or revert statement, you’ll need to diagnose why the condition isn’t met and then resolve it. Typically, this involves verifying input parameters, state variables, or contract conditions.
The following is the Lock.sol contract with a require statement that validates that the parameter you are passing (_unlockTime) must be greater than the current block.timestamp.
A simple solution to troubleshoot this error is to log the value of block.timestamp and _unlockTime, which will help you compare these values and then ensure that you are passing the correct ones:
npx hardhat test, you’ll then see the following:
block.timestamp and the value you are passing, which makes it easier to detect the error.
Unintended behavior errors
Unintended behavior errors occur when you introduce unexpected behavior into the codebase due to a misunderstanding in the way Solidity works. In the following example,LockCreator is a contract that allows anybody to deploy a Lock.sol instance. However, the LockCreator contains an error: the createLock functions are able to accept Ether to be locked but the amount sent is not being transferred to the Lock contract:
LockCreator.test.ts that can identify the error and then solve it:
0:
LockCreator was something you may have overlooked.
The solution is to modify the createLock function with:
Out-of-bounds errors
Attempting to access arrays at an invalid position can also cause errors. If you wish to retrieve all theLock contract instances being created in the previous example, you can make the locks array public. In order to illustrate this example, though, you can create a custom function called getAllLocks:
if statement compares <= against the length of the array, so it tries to access the element in position 1, and crashes.
Here’s the simple solution:
Conclusion
In this tutorial, you’ve learned some techniques about how to debug smart contracts using Hardhat. You explored some common cases of various errors and how by simply usingconsole.log and a proper test, you can identify and solve the problem.