Circuit Declaration

Basic Syntax

circuit c(a: A, b: B): R {
    // circuit body
}

export circuit name(): [] {
    // exported circuit body
}

Each path through the body must end with a return unless the return type is [].

Source: Circuits

Let’s break this down:

PartMeaning
exportMakes the circuit publicly callable
circuitKeyword declaring a circuit
nameThe circuit’s identifier
()Parameter list (empty here)
[]Return type (empty tuple = no return)
{ }Circuit body

⚠️ Critical: Return Type Syntax

Circuits that don’t return a value use [] (empty tuple), NOT Void:

export ledger counter: Counter;

// ✅ CORRECT
export circuit doSomething(): [] {
    counter.increment(1);
}
export ledger counter: Counter;

// ❌ WRONG - fails with "unbound identifier Void" (try it!)
export circuit doSomething(): Void {
    counter.increment(1);
}

Visibility

Exported Circuits

Use export to make circuits callable from TypeScript:

// Can be called from TypeScript
export circuit publicAction(): [] {
    // ...
}

Internal Circuits

Without export, circuits are internal (callable only within Compact):

// Only callable from other circuits
circuit internalHelper(): Field {
    return 42;
}

Source: Exported circuits

Generic Circuits

Circuits can have type parameters, making them reusable with different types:

circuit id<T>(value: T): T {
    return value;
}

circuit first<A, B>(pair: [A, B]): A {
    return pair[0];
}

Source: Generic parameter references

Complete Example

pragma language_version >= 0.16;

import CompactStandardLibrary;

export ledger balance: Counter;

// Public circuit - callable from TypeScript
export circuit deposit(amount: Uint<16>): [] {
    balance.increment(disclose(amount));
}

// Internal circuit - helper for other circuits
circuit getMinimum(): Uint<16> {
    return 10;
}

// Public circuit using internal helper
export circuit depositMinimum(): [] {
    const min = getMinimum();
    balance.increment(min);
}

Source: Writing a contract

Exercises

Complete exercises/03_circuits/01_basic_circuit/.