Events and Errors
Events
Events are like logs that your contract emits when something important happens. External applications (wallets, explorers, dApps) can listen for these events to track contract activity.
Declare events using SkittlesEvent<T> as a class property:
import { address, SkittlesEvent, Indexed } from "skittles";
class Token {
Transfer: SkittlesEvent<{
from: Indexed<address>;
to: Indexed<address>;
value: number;
}>;
}
Indexed Parameters
Indexed parameters can be used to filter and search for specific events. For example, you can search for all Transfer events involving a specific address.
Wrap parameter types with Indexed<T> to mark them as indexed in the event. Up to 3 parameters per event can be indexed.
Transfer: SkittlesEvent<{
from: Indexed<address>; // indexed
to: Indexed<address>; // indexed
value: number; // not indexed (stored in data)
}>;
Emitting Events
Emit events using this.EventName.emit(...). There are two syntaxes:
Object literal syntax:
this.Transfer.emit({ from: msg.sender, to, value: amount });
Positional argument syntax:
this.Transfer.emit(msg.sender, to, amount);
Event Alias
You can also use Event as a shorter alias for SkittlesEvent:
import { Event } from "skittles";
class Token {
Transfer: Event<{ from: address; to: address; value: number }>;
}
Custom Errors
Custom errors give clear, structured error messages when something goes wrong. They're more informative and cost less gas than simple string messages.
There are two ways to declare them.
SkittlesError Property
Declare errors as class properties using SkittlesError<T>:
import { address, SkittlesError } from "skittles";
class Token {
InsufficientBalance: SkittlesError<{
sender: address;
balance: number;
required: number;
}>;
transfer(to: address, amount: number): void {
if (this.balances[msg.sender] < amount) {
throw this.InsufficientBalance(
msg.sender,
this.balances[msg.sender],
amount,
);
}
// ...
}
}
Throw custom errors with throw this.ErrorName(args...).
Error Class Pattern
Alternatively, declare errors as classes that extend Error:
class InsufficientBalance extends Error {
constructor(sender: address, balance: number, required: number) {}
}
class Token {
transfer(to: address, amount: number): void {
if (this.balances[msg.sender] < amount) {
throw new InsufficientBalance(
msg.sender,
this.balances[msg.sender],
amount,
);
}
}
}
Simple Reverts
Use throw new Error('message') for simple error messages:
if (amount == 0) {
throw new Error("Amount must be greater than zero");
}
A bare throw stops execution immediately.