Enums

Enums (enumerations) define a type with a fixed set of named values. They’re perfect for representing states, choices, or categories.

Source: User-defined types

Declaring an Enum

Use the enum keyword followed by the type name and variant names:

enum GameState { waiting, playing, finished }

Variants are separated by commas. A trailing comma is allowed but not required.

enum Direction {
    north,
    east,
    south,
    west,
}

Accessing Enum Variants

Use dot notation to access enum variants:

enum GameState { waiting, playing, finished }
enum Direction { north, east, south, west }

export pure circuit variants(): GameState {
    const state = GameState.waiting;
    const dir = Direction.north;
    return state;
}

Source: User-defined types

Note: Use dot notation to access enum variants: GameState.waiting

Comparing Enums

Compare enum values with == and !=:

enum Status { pending, approved, rejected }

export pure circuit isApproved(status: Status): Boolean {
    return status == Status.approved;
}

export pure circuit notRejected(status: Status): Boolean {
    return status != Status.rejected;
}

Source: Writing a contract

Enums in Control Flow

Enums work naturally in conditionals:

enum GameState { waiting, playing, finished }

export pure circuit canJoin(state: GameState): Boolean {
    if (state == GameState.waiting) {
        return true;
    }
    return false;
}

export pure circuit getStateMessage(state: GameState): Uint<8> {
    if (state == GameState.waiting) {
        return 0;  // "Waiting for players"
    }
    if (state == GameState.playing) {
        return 1;  // "Game in progress"
    }
    return 2;  // "Game finished"
}

Default Values

The default value of an enum is its first variant:

enum Status { pending, approved, rejected }

export pure circuit defaultStatus(): Status {
    const s = default<Status>;  // Status.pending (first variant)
    return s;
}

Source: Default values

Enums in Ledger State

Enums can be stored directly in ledger fields:

enum ContractState { initialized, active, paused, terminated }

export ledger state: ContractState;

Source: Declaring public state

Enums in Structs

Enums work well as struct fields:

enum OrderStatus { pending, processing, shipped, delivered, cancelled }

struct Order {
    orderId: Uint<64>,
    customerId: Bytes<32>,
    amount: Uint<64>,
    status: OrderStatus
}

export ledger orders: Map<Uint<64>, Order>;

Source: User-defined types

Casting Enums to Field

Enums can be cast to Field type:

enum Choice { rock, paper, scissors }

export pure circuit paperIndex(): Field {
    // Enum to Field (by variant index: rock=0, paper=1, scissors=2)
    const choiceField = Choice.paper as Field;  // 1
    return choiceField;
}

Note: Enums also cast to Uint<n> (conversion, yielding the variant index), and integers cast back to enums as a checked cast — it compiles and runs, but fails at runtime if the value exceeds the last variant index (e.g., 5 is greater than maximum enum value 2). Verified with toolchain 0.31.1.

Source: Type casts

Exporting Enums

To use an enum from TypeScript, you must export it:

// ✅ Accessible from TypeScript
export enum GameState { waiting, playing, finished }

// ❌ Not accessible from TypeScript (internal only)
enum InternalState { a, b, c }

Source: Top-level exports

TypeScript Representation

Enum values are represented as numbers at runtime in JavaScript/TypeScript:

// Compact
export enum GameState {
  waiting,
  playing,
  finished,
}

// TypeScript runtime representation - numeric values
// waiting = 0, playing = 1, finished = 2

Source: Contract constructor

Common Patterns

State Machine

Enums are ideal for representing state machines:

enum AuctionState { open, closed, finalized }

export ledger auctionState: AuctionState;

// Check state in pure circuits
export pure circuit isOpen(state: AuctionState): Boolean {
    return state == AuctionState.open;
}

export pure circuit isClosed(state: AuctionState): Boolean {
    return state == AuctionState.closed;
}

Multiple Choice

enum Vote { yes, no, abstain }

struct Ballot {
    voter: Bytes<32>,
    choice: Vote
}

export ledger ballots: Map<Bytes<32>, Ballot>;

// Pure circuit to check vote
export pure circuit isYesVote(vote: Vote): Boolean {
    return vote == Vote.yes;
}

export pure circuit isNoVote(vote: Vote): Boolean {
    return vote == Vote.no;
}

Complete Example

pragma language_version >= 0.16;

// Game states
export enum GamePhase { setup, betting, reveal, payout }

// Player choices
export enum Choice { rock, paper, scissors }

// Game result
export enum Result { player1Wins, player2Wins, draw }

// Determine winner based on choices
export pure circuit determineWinner(p1: Choice, p2: Choice): Result {
    // Draw if same choice
    if (p1 == p2) {
        return Result.draw;
    }

    // Rock beats scissors
    if (p1 == Choice.rock) {
        if (p2 == Choice.scissors) {
            return Result.player1Wins;
        }
        return Result.player2Wins;
    }

    // Paper beats rock
    if (p1 == Choice.paper) {
        if (p2 == Choice.rock) {
            return Result.player1Wins;
        }
        return Result.player2Wins;
    }

    // Scissors beats paper
    if (p2 == Choice.paper) {
        return Result.player1Wins;
    }
    return Result.player2Wins;
}

// Check if game is in specific phase
export pure circuit isSetupPhase(phase: GamePhase): Boolean {
    return phase == GamePhase.setup;
}

export pure circuit isBettingPhase(phase: GamePhase): Boolean {
    return phase == GamePhase.betting;
}

Exercises

Complete exercises/05_user_types/02_enums/.