The try-Catch mechanism and how it improves error handling in Solidity. (Error Handling In Solidity, pt.3)
The try-Catch mechanism and how it improves error handling
Error handling has been so exciting. It opens us to the world of secured code in solidity. In the first part of error handling, we talked about the importance of error handling in solidity, potential risks and vulnerabilities, and the impact of error handling on user experience and contract security.
In the second part, we talked about The different types of exceptions that can occur in Solidity contracts, like Assertion Failure, Out-of-Gas Exceptions, Invalid Operations, Revert and Require Statements, External Call Exceptions, Custom exceptions, and Low-Level exceptions, with their code examples.
Now we will be talking about the try-catch mechanism and how it improves error handling.
From solidity documentation,
Solidity also supports exception handling in the form of try/catch-statements, but only for external function calls and contract creation calls.
This means that try/catch statements can be used when calling functions of other contracts or creating new contracts, but not for handling exceptions that occur within the normal execution flow of the current contract.
The try/catch mechanism in Solidity allows developers to catch and handle exceptions that may occur during external contract calls using the low-level call
, delegatecall
, staticcall
, and create
functions.
The syntax of a try/catch statement in Solidity looks like this:
When exceptions happen in a sub-call, they “bubble up” (i.e., exceptions are rethrown) automatically unless they are caught in a try/catch statement. Exceptions to this rule are send and the low-level functions call, delegatecall and staticcall: they return false as their first return value in case of an exception instead of “bubbling up”.
This means that if an external contract call or contract creation encounters an exception (e.g., reverts due to a require statement or runs out of gas), the exception will automatically propagate upward to the calling contract, and any subsequent calls made by that contract will also be reverted.
There are exceptions to this "bubble up" rule when using certain low-level functions. Specifically, the send
function and the low-level functions call
, delegatecall
, and staticcall
behave differently when it comes to handling exceptions.
How try/catch improves error handling in solidity
The try/catch mechanism brought significant improvements to error handling in Solidity contracts. Let's discuss how the try-catch mechanism works and the benefits it offers:
Exception Handling: The try-catch mechanism enables structured exception handling in Solidity contracts. It allows developers to encapsulate code within a try block and catch and handle specific exceptions in the catch block. This facilitates more granular error handling, making contracts more robust and secure.
Handling Unhandled Exceptions: Previously, unhandled exceptions would revert the entire transaction, discarding any state changes made before the exception occurred. With the try-catch mechanism, unhandled exceptions can be caught, allowing for better recovery and handling of exceptional conditions.
Catching Specific Exceptions: Developers can specify the types of exceptions they want to catch in the catch block. This allows for fine control over error handling. By catching specific exceptions, developers can handle different exceptional scenarios differently, providing more targeted responses or recovery strategies.
Multiple Catch Blocks: Solidity's try-catch mechanism allows for multiple catch blocks, each targeting a specific type of exception. This enables developers to define different error-handling logic for different exception types, enhancing flexibility in handling various exceptional conditions.
Nesting Try-Catch Blocks: Developers can nest try-catch blocks within each other, creating a hierarchical structure for error handling. This allows for handling exceptions at different levels of code execution and enables developers to handle errors at appropriate levels of fineness.
Error Propagation: The try-catch mechanism provides better control over error propagation. Developers can choose to catch and handle exceptions within the contract or propagate them further up the call stack by not catching them. This flexibility allows for customized error-handling strategies based on the specific needs of the contract and its interactions with other contracts.
Enhanced Contract Resilience: With the try-catch mechanism, contracts can gracefully handle exceptions, recover from exceptional conditions, and continue execution or provide fallback actions where appropriate. This improves the overall resilience of contracts, reducing the likelihood of transaction reverts and providing a better user experience.
Below is a Solidity contract demonstrating how to use try/catch for an external call;
In this contract, we have two contracts:
CallerContract
: This contract makes an external call to theTargetContract
. It uses a try-catch block to handle exceptions that may occur during the external call.TargetContract
: This contract is the target of the external call made byCallerContract
. It demonstrates various aspects of try-catch handling, including handling multiple exceptions, nesting try-catch blocks for sub-call exceptions, reverting operations to trigger exceptions, and creating a custom exception with a specific error message.
Please note that the TargetContract
contains a custom error definition named CustomError
, which is used to provide specific error messages for certain exceptional conditions.
When callExternalFunction
is called in CallerContract
, it will make an external call to TargetContract
's processData
function. Depending on the value of the data
parameter, different exceptions may be triggered. The try-catch blocks in both contracts allow graceful handling of these exceptions and provide meaningful error messages.
Had fun with try/catch? Now, this isn't the end of our error-handling series. We will be going further in the next part. Guess what we will be talking about... 🤔
We will be talking about the differences between assert and require statements in Solidity, when to use assert and require statements based on the expected behavior and contract logic, and examples illustrating the appropriate use of assert and require statements for error handling.
Check out my other articles on Solidity Basics (Solidity Data Types and Operators)**, [solidity inheritance](favourajaye.hashnode.dev/solidity-inheritance), Solidity fallback function and function overloading, Variables and control structures in solidity, Solidity Functions, Libraries in solidity, Abstract contracts and Interfaces in solidity, [Guidelines on becoming a Blockchain Developer in 2023 (Solidity)](medium.com/coinsbench/guidelines-on-becomin..), [What is blockchain?](medium.com/web3-magazine/what-is-blockchain..), [All you need to know about web 3.0](medium.com/web3-magazine/all-you-need-to-kn..), [Solidity: Floating points and precision](medium.com/@favoriteblockchain/solidity-flo..), and others
Click here to see the Github repo for this 100 days of solidity challenge.
Don’t forget to follow me, put your thoughts in the comment section, and turn on your notifications.
Subscribe to my newsletter
Read articles from Favour Ajaye directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Favour Ajaye
Favour Ajaye
smart contract developer