Skip to content
LogoLogo

Errors

Errors are typed and declared, and each compiles to a Solidity custom error. External functions list every error they can raise, and the compiler checks the list.

errors.lithe
(* Errors are typed and declared. Each compiles to a Solidity custom error. *)
 
(* No payload: `Unauthorized()` *)
import "std/evm";
 
error Unauthorized;
 
(* One positional value: `TooSmall(uint256)`, in the ABI as `TooSmall(uint256)` *)
error TooSmall of uint;
 
(* Named fields: `InsufficientBalance(uint256 available, uint256 required)` *)
error InsufficientBalance of record {
  available : uint;
  required : uint;
}
 
(* A named set of errors, for reuse in `raises`. *)
errors withdrawErrors is
  | TooSmall
  | InsufficientBalance
 
storage is record {
  owner : address;
  balances : map(address, uint);
}
 
(* An internal function's errors are inferred when `raises` is left off. *)
view function requireOwner() is {
  assert(Evm.sender() = storage.owner, Unauthorized);
}
 
(* An external function must declare every error it can raise. *)
external function withdraw(const amount : uint)
  raises withdrawErrors
is {
  assert(amount >= 100, TooSmall(amount));
  const have : uint := storage.balances[Evm.sender()];
  if have < amount then {
    fail InsufficientBalance { available = have; required = amount; };
  }
  storage.balances[Evm.sender()] := have - amount;
}
 
external function reset(const who : address)
  raises Unauthorized
is {
  requireOwner();
  storage.balances[who] := 0;
}

Leave TooSmall out of withdrawErrors and compilation fails:

external function `withdraw` may raise `TooSmall`

lithe errors errors.lithe prints every error's selector and which entrypoints raise it.