Skip to main content

Ledger State

The public ledger state is stored on-chain and visible to anyone via the Indexer GraphQL API. All values are set via disclose() calls inside circuits.

Public Ledger Variables

// ─── Circle Parameters (set once on createCircle) ───────────────
export ledger contributionAmount: Uint<64>;
export ledger memberCap: Uint<8>;
export ledger roundCount: Uint<8>;
export ledger roundDuration: Uint<64>;

// ─── Round State ─────────────────────────────────────────────────
export ledger currentRound: Counter;
export ledger circleStatus: CircleStatus;
export ledger contributionsThisRound: Cell<Uint<8>>;
export ledger roundDeadline: Cell<Uint<64>>;
export ledger payoutClaimed: Cell<Boolean>;

// ─── Membership ──────────────────────────────────────────────────
export ledger memberTree: MerkleTree<4, Bytes<32>>;
export ledger memberCount: Cell<Uint<8>>;

// ─── Privacy Enforcement ─────────────────────────────────────────
export ledger spentIdentifiers: Set<Bytes<32>>;

Field Reference

Circle Parameters

FieldTypeDescription
contributionAmountUint<64>Fixed NIGHT amount each member contributes per round. In smallest denomination (1,000,000 = 1 NIGHT).
memberCapUint<8>Maximum number of members. Bounded by Merkle tree depth: MerkleTree<4> allows up to 16.
roundCountUint<8>Total number of rounds. In a standard ROSCA, equals memberCap.
roundDurationUint<64>Duration of each round in block timestamps (seconds on local dev).

Round State

FieldTypeDescription
currentRoundCounterZero-indexed round counter. Increments on each claimPayout().
circleStatusCircleStatusCurrent lifecycle state. See State Machine.
contributionsThisRoundCell<Uint<8>>Number of contributions received in the current round. Resets to 0 at round start.
roundDeadlineCell<Uint<64>>Block timestamp deadline for the current round.
payoutClaimedCell<Boolean>Whether the payout has been claimed for the current round. Prevents double-claiming.

Membership

FieldTypeDescription
memberTreeMerkleTree<4, Bytes<32>>Sparse Merkle tree of member identity commitments. Depth 4 = up to 16 leaves. Each leaf is persistentCommit(secret, nonce).
memberCountCell<Uint<8>>Number of members who have joined. Determines leaf insertion index.

Privacy Enforcement

FieldTypeDescription
spentIdentifiersSet<Bytes<32>>Set of `persistentHash(secret

Reading Ledger State

Via the Indexer GraphQL at http://localhost:8088/api/v1/graphql:

query CircleState($address: String!) {
contract(address: $address) {
ledger {
contributionAmount
memberCap
roundCount
currentRound
circleStatus
memberCount
contributionsThisRound
roundDeadline
payoutClaimed
memberTree {
root
}
}
}
}

Via the TypeScript DApp layer:

import { getLedgerState } from '@/dapp/interact';
import { createProviders } from '@/dapp/providers';

const providers = await createProviders();
const state = await getLedgerState(providers, contractAddress, contractModule);
// Returns CircleLedgerState with JS-typed fields

CircleStatus Enum

enum CircleStatus {
OPEN, // accepting members
ACTIVE, // (transitional — unused in final impl)
ROUND_IN_PROGRESS,// contributions being collected
PAYOUT_PENDING, // all contributed, awaiting claim
DEFAULT_DETECTED, // deadline passed with missing contributions
COMPLETED // all rounds done
}