Error Handling in Solidity: Safeguard Your Smart Contracts

In blockchain development, errors aren’t just bugs—they’re potential financial disasters. Solidity provides robust tools to handle failures gracefully. Let’s explore how to manage exceptions and protect your contracts.

Why Proper Error Handling Matters

  • πŸ’Έ Prevent fund loss from invalid operations
  • πŸ”’ Secure contracts against malicious inputs
  • πŸ“‰ Reduce debugging time with clear reverts

Core Error Handling Tools

Function Usage Gas Refund
require Input validation Yes
revert Complex conditions Yes
assert Invariant checks No

1. require(): Input Validation Guard

function transfer(address to, uint256 amount) public {
    require(amount <= balances[msg.sender], "Insufficient balance");
    require(to != address(0), "Invalid recipient");
    
    balances[msg.sender] -= amount;
    balances[to] += amount;
}
  • ✅ Use for user input validation
  • πŸ’‘ Provides revert reason string
  • ⛽ Refunds remaining gas

2. revert(): Complex Error Handling

function withdraw(uint256 amount) public {
    if (amount > balances[msg.sender]) {
        revert("Withdrawal amount exceeds balance");
    }
    if (block.timestamp < lockTime[msg.sender]) {
        revert("Funds are locked");
    }
    
    balances[msg.sender] -= amount;
}
  • 🎚️ Handles multiple conditions
  • πŸ“¦ Can use custom errors for gas savings

3. assert(): Invariant Protector

function divide(uint256 a, uint256 b) public pure returns(uint256) {
    uint256 result = a / b;
    assert(b != 0); // Should never fail
    return result;
}
  • πŸ›‘ Use for internal consistency checks
  • πŸ”₯ Consumes all gas on failure (post 0.8.0)

4. try/catch: External Call Safety

try otherContract.execute{value: 1 ether}() {
    emit Success();
} catch Error(string memory reason) {
    emit Failure(reason);
} catch (bytes memory) {
    emit GenericFailure();
}
  • 🎯 Only works with external calls
  • 🧩 Catches specific error types

⚠️ Common Mistakes

  • Using assert for input validation
  • Empty revert messages ("Something failed")
  • Ignoring return values from low-level calls

Best Practices

  1. Use custom errors for frequent reverts
  2. Validate all external inputs with require
  3. Reserve assert for impossible states
  4. Test error paths thoroughly

Custom Errors (Solidity ≥0.8.4)

error InsufficientBalance(uint256 available, uint256 required);

function withdraw(uint256 amount) public {
    if (amount > balances[msg.sender]) {
        revert InsufficientBalance(balances[msg.sender], amount);
    }
    // ...
}

→ Saves gas compared to string messages

Your Challenge

Improve this vulnerable function:

function buyTokens(uint256 amount) public payable {
    if (msg.value != amount * tokenPrice) return;
    // Proceed with transfer
}

Error Handling Tools

  • πŸ” Hardhat Console Logging
  • πŸ“œ Tenderly Debugger
  • πŸ§ͺ Foundry’s expectRevert

Comments

Popular posts from this blog

Mastering Events & Logging in Solidity: The Blockchain’s Communication Channel

πŸ”’ Secure Your Code: Top 5 Solidity Vulnerabilities & Proven Fixes

πŸ”₯ Gas Fees Demystified: The Ultimate Guide to Efficient Smart Contracts