Identifying Common Errors
When working with smart contracts, especially on the ICB Network, it's important to recognize and understand common errors that may occur during development. Being able to identify and resolve these issues efficiently is a key part of the debugging process.
In our ICB Learn tutorial series, we address several compile-time errors in the Error Triage section. However, other issuesβsuch as transaction reverts or out-of-bounds array accessβcan surface unexpectedly during contract execution.
In the sections below, you'll explore proven techniques to help you debug and troubleshoot these runtime errors effectively.
Revert Errors
When a transaction fails because of a require or revert statement, it's essential to investigate why the condition wasn't satisfied. This often means checking input parameters, contract state variables, or specific conditions within the logic.
For example, in the Counter.sol contract, there's a require statement that ensures the newNumber parameter is less than 100. To debug this type of error, a practical approach is to log newNumber:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;
import "hardhat/console.sol";
contract CounterError {
uint256 public number;
uint256 public constant MAX_NUMBER = 100;
address public owner;
constructor() {
owner = msg.sender;
console.log("Contract deployed by:", owner);
console.log("Initial number:", number);
console.log("MAX_NUMBER:", MAX_NUMBER);
}
function setNumber(uint256 newNumber) public {
console.log("setNumber called with:", newNumber);
console.log("Current number:", number);
console.log("Caller:", msg.sender);
console.log("Owner:", owner);
console.log("MAX_NUMBER:", MAX_NUMBER);
require(msg.sender == owner, "Only owner can set the number");
require(newNumber <= MAX_NUMBER, "Number cannot exceed maximum limit");
number = newNumber;
console.log("Number successfully set to:", newNumber);
}
function increment() public {
console.log("increment called");
console.log("Current number:", number);
console.log("Caller:", msg.sender);
require(msg.sender == owner, "Only owner can increment");
require(number < MAX_NUMBER, "Cannot increment: would exceed maximum");
number++;
console.log("Number incremented to:", number);
}
function getState() public view returns (
uint256 currentNumber,
uint256 maxNumber,
address currentOwner
) {
return (number, MAX_NUMBER, owner);
}
}
When you run the tests with npx hardhat test, you'll then see the following:

You can now clearly see the value of newNumber, which makes it easier to identify the issue. In this case, it's evident that newNumber is less than 100, which explains why the condition fails.
Unintended Behavior Errors
You can write a test file named CounterCreat.test.js to help detect the issue and implement a solution.
The terminal output below shows that the balance is 0:

Although this issue can be caught by writing more comprehensive test cases with proper assertions, the missing transfer of Ether from CounterCreator to the Counter contract is an important detail that might have been unintentionally overlooked.
To resolve this, you should update the createCounter function as follows:
Out-of-Bounds Errors
Accessing an array with an invalid index can result in runtime errors.
For example, in a CounterCreator contract, you might use a custom function like this to retrieve all Counter contract instances:
However, this implementation contains a common mistake: the loop condition i <= counters.length causes an out-of-bounds access on the last iteration. It should be i < counters.length instead.
While you could make the counters array public to access the data directly, using a custom function like getAllCounters is useful for illustrating and controlling how the data is exposed.
You can verify the function using the following test case:
Which will then throw an error:

You can include some debugging logs to identify the issue:
Then, you see the following in the terminal:

Since arrays in Solidity are zero-indexed, an array containing one item stores that item at index 0. In the example above, the if statement uses <= in the loop condition, which causes it to attempt access at index 1βan invalid positionβresulting in a crash.
Here's a straightforward fix:
Which immediately solves the problem:

Last updated