Unlike the debugging process in Web2, dealing with code errors and finding the root cause is highly time-consuming in Web3. This can be not only tiring for engineers, but also highly expensive for the Ethereum community. Luckily, as Ethereum adoption continues to grow so does the number of possible options that can greatly simplify and speed up debugging.

With an advanced tool for debugging Solidity Smart Contracts, you can easily identify the reason why a specific transaction or contract execution failed. Once you determine what type of error caused a certain issue and gather in-depth information on the nature of the error, you can implement an appropriate solution.

What are some common Ethereum Smart Contract errors?

When it comes to Solidity Smart Contracts, runtime and logic errors are the most common issues engineers come across when writing or executing code.

Runtime errors

Runtime errors occur after deploying Smart Contract code on the Ethereum blockchain. In the case of runtime errors, the Ethereum Virtual Machine (EVM) may identify your code as faulty or believe that you’re running a transaction that’s against the logic of a Smart Contract. Runtime errors occur during Smart Contract execution.

Typical runtime errors include the following:

1. Execution reverted errors occur when a called Smart Contract decides to prevent further execution of a transaction that goes against its business logic. The Smart Contract code usually contains checks for various required conditions. If a transaction fails to meet even a single condition, the contract considers it invalid and reverts its execution.

In the case of these errors, the author of the Smart Contract introduces them intentionally as a way to reject invalid transactions. By using requirement statements, the developer makes sure that transactions meet certain logical criteria. This way, they prevent more serious issues from happening.

For example, a Smart Contract will execute only if it's called with a particular amount of Ether transferred. If a transaction contains a different amount, it’ll be reverted. This is an error from the transaction sender’s point of view, but it’s actually a valid response to an invalid transaction from the contract’s point of view.

You’ll also come across this type of error when trying to transfer tokens even though you don’t have any. In the Smart Contract code, these errors are implemented in the following way: `require(myTokens >=0, “Insufficient amount of tokens”)`.

2. Out of gas errors occur when you don’t have enough ETH/Gwei to pay gas for running a transaction.

3. Invalid JUMP errors are another type of runtime errors. They happen if you try to call a function that doesn’t exist in the called contract or if you jump to an address which isn’t a valid JUMP destination when writing inline-assembly.

5. Stack overflow errors take place most commonly when you’re trying to call a function recursively and the termination condition is never met. In the case of Solidity Smart Contracts, recursive functions can happen only 1024 times because of the Solidity stack frame limit. If you execute a recursive function more than that, a stack overflow error will occur.

6. Stack underflow errors will happen in the execution of assembly code. If the inline-assembly code tries to execute a POP on top of an empty stack, this error will occur.

7.  Lastly, there are invalid opcode errors that aren’t that common. They occur when the EVM gets “confused” when it encounters an incompatibility with a Smart Contract. For example, this happens when a different version of the compiler gets used instead of the one the network expects.

How to debug runtime errors

A simple way to handle the debugging process is to use Tenderly Debugger. This tool streamlines debugging Smart Contracts as it allows you to easily identify the exact line of code where an error occurred and analyze values of local and state variables. This can help you come up and even try out possible solutions to fix the error in the code or change your transaction to a new one that will execute successfully.

You can easily access Debugger by signing up with Tenderly and setting up your account. Once you sign up, you’ll find the Transaction tab on the left from which you can access this feature. Another quick way to access Tenderly Debugger is to install the Chrome extension that will enable you to open any transaction in Tenderly directly from block explorers.

Once in Tenderly, you can start dissecting code and debugging Solidity Smart Contracts.

1. Debugging execution reverted errors

Tenderly Debugger will clearly show which type of error caused a transaction to fail. In this case, an “execution error” message will be visible. You’ll get easy-to-understand yet detailed information about why the error happened.

When you open Debugger, the Stack Trace section provides an overview of the function call sequence leading up to the error and the exact line of code where the error happened. You can dive deeper into the cause by using the Execution Trace to trace the error back to its root.

Here, you can switch between the Function Trace and Call Trace to filter relevant calls. Finally, the section at the bottom allows you to fully understand the EVM instruction you’re inspecting.

After clicking the Debug Error button, you can start analyzing the code and determine a possible solution. For execution reverted errors, the State Changes tab in the navigation menu above might also be helpful as it shows an overview of all the state changes within the Smart Contract.

2. Debugging out of gas errors

Out of gas errors are also clearly marked, with precise information on a transaction’s gas usage.

Once in Tenderly, you can easily take steps to optimize your Smart Contract and reduce gas fees for future transactions. For this purpose, you can use Gas Profiler to understand exactly how much gas every function call within your transaction spent.

A flame graph provides you with a visual representation, so you can easily navigate through transaction function costs. After getting in-depth information, you’ll know exactly which functions to optimize to reduce gas usage.

3. Debugging invalid opcode, stack overflow & stack underflow errors

You can use Tenderly Debugger to understand these errors the same way you’d use it to debug execution reverted errors – the tooling works just the same. The only difference is that these types of errors are triggered by the EVM as they violate the EVM specification.

Logic errors

Logic errors occur when a Smart Contract has loopholes and the code executes in unexpected and most likely unwanted ways without failures. This makes Smart Contracts vulnerable to possible hacks. These errors usually happen because of the mistakes and oversights made during development.

In the case of logic errors, the EVM doesn’t even register Smart Contract code as faulty as it can correctly execute it on-chain. The errors actually come from successful transactions with undesired and usually unpredicted outcomes.

An example of such an error is the well-known DAO Re-Entrancy attack where a hacker was able to steal $70 million worth of Ether because of a development mistake. The engineer behind the Smart Contract logic didn’t update user balance before transferring ETH. Although the re-entrancy attack is based on a simple mistake, malicious coders still use it to steal valuable assets.

Another example is the Cream Finance attack with a more complex logic error. In this hack, the attackers were able to steal $130 million worth of assets.

How to debug logic errors

There are ways to prevent such great losses if you establish an efficient framework for debugging. Tenderly Debugger allows you to respond to hacks quickly, identify the root cause, and work toward a possible solution. You can debug logic errors that leave your Smart Contracts vulnerable to attacks by combining the following features:

Function Trace: This is your go-to tool when it comes to understanding the logic of your code in depth.

It sequentially lists the internal and external calls within your Smart Contract, enabling you to go through a transaction step-by-step. The Function Trace gives you an insight into how every piece of code was executed.

You’ll also be able to easily identify the caller and the contract, the input and the output of each individual call, as well as the cumulative state changes the transaction made in every contract it interacted with. This greatly facilitates the debugging process.

Call Trace: This feature lists only external calls sequentially. This way, you can narrow down the list of execution calls to those that invoked a certain function and may be the cause of an attack.

Evaluate Expression: Instead of doing time-consuming calculations to get the information you need, use Evaluate Expression. You can easily evaluate complex and simple expressions involving function parameters, local variables, and state variables of a contract, getting expression results in just a few clicks. To make the most of this feature, learn how to use Evaluate Expression to streamline debugging.

Prioritization: Using this feature, you can flag suspicious lines of code for priority.

You can assign different priority levels, directing your team members to those lines of code that are most likely behind an attack. This gives both your team and yourself clarity and speed, especially when you’re simultaneously figuring logic errors in your Smart Contract.

Annotation: To further simplify the debugging process, add comments to the code using the Annotation option. This allows you to speed up the collaboration with your teammates or leave notes for yourself to address certain issues later on.

State Changes: You’re able to inspect state changes within a specific transaction and examine any changed value. In the example below, you'll see how much the balance of two addresses changed (the first one increased, the second one decreased).

Debug Ethereum Smart Contracts with ease

Whatever type of Smart Contract errors you’re dealing with, it’s important to establish an efficient debugging process so you can address potential issues as soon as they arise. With Tenderly Debugger, you get an advanced tool for debugging Solidity Smart Contracts that will guide you through your entire debugging flow. Find an approach that works for you and prevent simple Smart Contract errors from turning into major issues or potential hacks.