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
- Use custom errors for frequent reverts
- Validate all external inputs with
require
- Reserve
assert
for impossible states - 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
Post a Comment