Back to Learn
errors
Error Handling
Define custom errors and handle failures gracefully in your contracts.
Error Handling
Proper error handling is crucial for secure smart contracts. Stylus uses Rust's Result type with custom Solidity-compatible errors.
Defining Errors
Use the sol! macro:
`` sol! { error InsufficientBalance(uint256 available, uint256 required); error Unauthorized(); }rust
`
Creating Error Enum
Wrap errors in an enum with SolidityError derive:
` #[derive(SolidityError)] pub enum MyError { InsufficientBalance(InsufficientBalance), Unauthorized(Unauthorized), }rust
`
Using Result
Return Result from functions:
` pub fn withdraw(&mut self, amount: U256) -> Result<(), MyError> { if balance < amount { return Err(MyError::InsufficientBalance(...)); } Ok(()) }rust
``
Code Example
#![cfg_attr(not(feature = "export-abi"), no_main)]
extern crate alloc;
use stylus_sdk::prelude::*;
use stylus_sdk::msg;
use stylus_sdk::storage::{StorageU256, StorageAddress};
use alloy_primitives::{Address, U256};
use alloy_sol_types::sol;
// Define errors
sol! {
error InsufficientBalance(uint256 available, uint256 required);
error Unauthorized();
error ZeroAmount();
}
// Wrap in enum
#[derive(SolidityError)]
pub enum VaultError {
InsufficientBalance(InsufficientBalance),
Unauthorized(Unauthorized),
ZeroAmount(ZeroAmount),
}
#[storage]
#[entrypoint]
pub struct Vault {
balance: StorageU256,
owner: StorageAddress,
}
#[public]
impl Vault {
pub fn withdraw(&mut self, amount: U256) -> Result<(), VaultError> {
// Check zero amount
if amount == U256::ZERO {
return Err(VaultError::ZeroAmount(ZeroAmount {}));
}
// Check authorization
if msg::sender() != self.owner.get() {
return Err(VaultError::Unauthorized(Unauthorized {}));
}
// Check balance
let current = self.balance.get();
if current < amount {
return Err(VaultError::InsufficientBalance(InsufficientBalance {
available: current,
required: amount,
}));
}
self.balance.set(current - amount);
Ok(())
}
}