Hardhat is a powerful Ethereum development environment that provides a variety of tools to simplify the development process. One of its standout features is the built-in Solidity debugger, which allows developers to debug their smart contracts effectively. This feature is invaluable for identifying issues and understanding the execution flow of your contracts.

What is the Hardhat Debugger?

The Hardhat debugger is an interactive tool that lets you inspect the state of your smart contracts during execution. It allows you to step through transactions, view variable values, and analyze the call stack, making it easier to identify bugs and understand how your code behaves.

Getting Started with the Hardhat Debugger

To use the Hardhat debugger, you first need to have a Hardhat project set up. If you haven't done this yet, you can create a new Hardhat project by running the following commands:

mkdir my-hardhat-project
cd my-hardhat-project
npx hardhat

Follow the prompts to create a sample project. Once your project is set up, you can write your Solidity contracts.

Sample Solidity Contract

Let's create a simple Solidity contract that we can debug:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract SimpleCalculator {
uint256 public result;

function add(uint256 x, uint256 y) public {
result = x + y;
}

function subtract(uint256 x, uint256 y) public {
require(x >= y, "x must be greater than or equal to y");
result = x - y;
}
}

This contract has two functions: add and subtract. The subtract function includes a require statement that can lead to a failure if not used correctly.

Deploying the Contract

Next, you need to deploy the contract. Create a new deployment script in the scripts directory:

// scripts/deploy.js
async function main() {
const SimpleCalculator = await ethers.getContractFactory("SimpleCalculator");
const calculator = await SimpleCalculator.deploy();
await calculator.deployed();
console.log("SimpleCalculator deployed to:", calculator.address);
}

main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});

Run the deployment script:

npx hardhat run scripts/deploy.js --network localhost

Using the Hardhat Debugger

Once your contract is deployed, you can start debugging. First, you need to run a local Hardhat network:

npx hardhat node

In another terminal, you can execute transactions against your contract. For example, you can call the add function:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract SimpleCalculator {
uint256 public result;

function add(uint256 x, uint256 y) public {
result = x + y;
}

function subtract(uint256 x, uint256 y) public {
require(x >= y, "x must be greater than or equal to y");
result = x - y;
}
}
0

If you want to debug a transaction, you can use the Hardhat console. Run:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract SimpleCalculator {
uint256 public result;

function add(uint256 x, uint256 y) public {
result = x + y;
}

function subtract(uint256 x, uint256 y) public {
require(x >= y, "x must be greater than or equal to y");
result = x - y;
}
}
1

In the console, you can interact with your deployed contract and trigger transactions. If a transaction fails, you can use the debugger to investigate it:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract SimpleCalculator {
uint256 public result;

function add(uint256 x, uint256 y) public {
result = x + y;
}

function subtract(uint256 x, uint256 y) public {
require(x >= y, "x must be greater than or equal to y");
result = x - y;
}
}
2

To debug the transaction, use the following command:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract SimpleCalculator {
uint256 public result;

function add(uint256 x, uint256 y) public {
result = x + y;
}

function subtract(uint256 x, uint256 y) public {
require(x >= y, "x must be greater than or equal to y");
result = x - y;
}
}
3

Replace // SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract SimpleCalculator {
uint256 public result;

function add(uint256 x, uint256 y) public {
result = x + y;
}

function subtract(uint256 x, uint256 y) public {
require(x >= y, "x must be greater than or equal to y");
result = x - y;
}
}
4 with the actual hash of the failed transaction. This will open the debugger, allowing you to step through the execution of the transaction.

Debugging Features

While debugging, you can:

  • Step Over: Move to the next line of code without entering function calls.
  • Step Into: Dive into the function calls to see their execution.
  • Inspect Variables: View the current state of variables at any point in the execution.
  • View Call Stack: See the sequence of function calls that led to the current point.

Conclusion

The built-in Solidity debugger in Hardhat is an essential tool for developers looking to debug their smart contracts efficiently. By allowing you to step through transactions and inspect the state of your contracts, it significantly simplifies the debugging process. Whether you're a beginner or an experienced developer, mastering the Hardhat debugger will enhance your development workflow and help you create more robust smart contracts.