As blockchain smart contracts developer, efficiency and clarity in smart contract development are always my top priority. Solidity, the most popular programming language for Ethereum smart contracts, introduced custom errors in version 0.8.4 via revert function and make it available in solidity 0.8.26 via require and could be used only via via-ir pipeline. This feature allows to optimize gas and improve the readability of error messages. This article provides a comprehensive walkthrough of Solidity custom errors, their advantages, why it must be used, and implementation.
Why Use Custom Errors?
Traditional methods of error handling in Solidity primarily rely on require
, revert
, and assert
statements with strings as error messages. While effective, these methods have limitations:
- High Gas Costs: Storing long error strings consumes more gas.
- Lack of Structure: Error strings provide limited context and can be challenging to parse programmatically.
Custom errors address these issues by:
- Reducing gas consumption, as error data is encoded compactly.
- Allowing developers to define structured errors with parameters, making debugging easier.
Gas Optimization Example
To understand the gas savings, consider the following comparison:
Using require
with an Error Message
require(condition, "Insufficient balance for withdrawal");
Using a Custom Error
error InsufficientBalance(address account, uint requested, uint available);
require(condition, InsufficientBalance(msg.sender, requestedAmount, availableBalance));
Gas Cost Analysis
-
require
with string: The gas cost increases with the length of the string. For example, a 32-character error message can add 200-300 gas. - Custom error: Encodes error data more compactly, reducing gas costs significantly. Using a custom error in this scenario can save ~100-150 gas per revert.
While savings may seem small per transaction, they add up significantly in high-frequency or large-scale dApps.
Syntax and Structure of Custom Errors
Custom errors are defined at the contract level using the error
keyword. Here's the basic syntax:
error CustomErrorName(string parameter1, uint parameter2);
You can then use require
with the custom error to abort execution and provide specific error details:
require(condition, CustomErrorName("Reason", 42))
Practical Example: Using Custom Errors
Let’s explore a practical example to understand how custom errors work.
Contract: Simple Bank
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
contract SimpleBank {
mapping(address => uint) private balances;
error InsufficientBalance(address account, uint requested, uint available);
function deposit() external payable {
balances[msg.sender] += msg.value;
}
function withdraw(uint amount) external {
uint balance = balances[msg.sender];
require(amount <= balance, InsufficientBalance(msg.sender, amount, balance);
balances[msg.sender] -= amount;
payable(msg.sender).transfer(amount);
}
function getBalance() external view returns (uint) {
return balances[msg.sender];
}
}
Explanation:
Defining the Error:
TheInsufficientBalance
error includes the account address, the requested withdrawal amount, and the available balance.Using the Error:
In thewithdraw
function, the contract checks if the requested amount exceeds the balance. If so, it usesrevert
withInsufficientBalance
to provide detailed error data.Gas Savings:
Unlike traditional error strings, custom errors reduce the gas cost by encoding error data in a compact form.
Interpreting Custom Errors in Transactions
When a transaction fails due to a custom error, the error details are accessible through the transaction’s revert reason. Tools like Etherscan, Hardhat, and Foundry can decode these errors, enabling developers to debug efficiently.
Enable via-ir in hardhat
here is how to enable via-ir pipeline:
const config: HardhatUserConfig = {
...
defaultNetwork: "sepolia",
solidity: {
version: "0.8.26", // any version you want
settings: {
viaIR: true,
},
};
Decoding Example:
Using Hardhat, you can decode custom errors as follows:
- Run the failing test or transaction.
- Use the debug output to inspect the revert reason.
Error: VM Exception while processing transaction: reverted with custom error 'InsufficientBalance'("0xYourAddress", 100, 50)
Best Practices for Custom Errors
- Be Descriptive: Define custom errors with meaningful names and parameters.
- Group Errors: If a contract has many errors, consider grouping them using comments or organizing them by functionality.
- Combine with Events: Use custom errors alongside events for comprehensive debugging and logging.
Conclusion
Custom errors in Solidity are a powerful tool for writing efficient and maintainable smart contracts. By reducing gas costs and improving error transparency, they enable to build optimized and readable smart contracts. Integrate custom errors into your projects today and elevate your smart contract development game!
Here a real example smart contracts that uses custom errors
Top comments (0)