Skip to main content

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.