Skip to content

Timing Windows

TIMLG rounds are slot-bounded: each phase is gated by Solana slot numbers recorded on-chain.

The timing model is designed to enforce the “Hawking Wall” principle: commitments must be made before the target randomness pulse is knowable.


Round parameters (MVP)

A round is created with parameters that define its timing and target:

Parameter Type Meaning
target_pulse_index u64 Which public randomness pulse is targeted (e.g., NIST index)
commit_open_slot u64 Slot when the commit window opens
commit_deadline_slot u64 Last slot where commits are accepted
reveal_deadline_slot u64 Last slot where reveals are accepted
claim_grace_slots u64 Grace period after reveal deadline before sweep closes claims

[!TIP] These protocol constants are defined in the on-chain program's constants.rs source file.

Notes:

  • Slots are the source of truth for enforcement. Wall-clock displays are approximate.
  • target_pulse_index is informational until the oracle posts the pulse; the on-chain checks rely on pulse_set and slot gating.
  • claim_grace_slots is configured at the protocol level (in Config) and applied by the operator.

Phase gating (what can happen when)

Phase Gate condition Allowed actions Notes
Commit slot <= commit_deadline_slot and pulse_set == false Create tickets (commit_ticket, batches) Commit stops at commit_deadline_slot. The pulse must not be set during commit.
Pulse posting slot >= commit_deadline_slot and pulse_set == false Oracle posts pulse (set_pulse_signed) The pulse must be posted after commits close. Posting is allowed from the boundary onward (`slot >= commit_deadline_slot`). Note that in the *boundary slot*, ordering matters: once `pulse_set = true`, commits are rejected even if `slot == commit_deadline_slot`.
Reveal pulse_set == true and slot <= reveal_deadline_slot Reveal tickets (reveal_ticket) Reveals are only valid once a pulse exists.
Finalize slot > reveal_deadline_slot and pulse_set == true Finalize round (finalize_round) Locks the round for settlement.
Token settlement slot > reveal_deadline_slot and round finalized Settle (settle_round_tokens) → enable claims Burns losers and burns NO-REVEAL stake. Winners become claimable.
Claim after token settlement and swept == false Users claim rewards (claim_reward) Claim refunds stake + mints reward. Claims are blocked once swept.
Ticket cleanup If round is alive: ticket.processed == true and (if ticket.win) ticket.claimed == true
If round is archived: round.lamports() == 0
Close ticket and reclaim its SOL rent deposit (close_ticket) close_ticket is user-signed and returns the ticket account’s lamports to the user (close = user). It is not part of token rewards.
Sweep (SOL + SPL) slot > reveal_deadline_slot + claim_grace_slots and round finalized Sweep SOL and tokens (sweep_unclaimed) MVP sweep transfers lamports to the SOL treasury and remaining tokens to the SPL treasury, then marks the round swept (closing claims).

The target pulse and “knowability”

The protocol assumes a public randomness source that is:

  • Unpredictable before it is published (e.g., NIST beacon pulses)
  • Publicly verifiable after publication

The “Hawking Wall” principle is enforced by:

  • requiring commits to happen before the pulse is posted (pulse_set == false)
  • only allowing reveals after the pulse exists (pulse_set == true)
  • binding each ticket to a bit index derived from ticket inputs (so users can’t choose the bit after seeing the pulse)

Edge cases and rules of thumb

1) Pulse arrives early or late (relative to expectations)

The oracle may be delayed or the network may vary. The protocol remains safe as long as:

  • the oracle does not post the pulse while commits are still allowed
  • users cannot reveal before the pulse is posted

Oracle Liveness Check (Safety Buffer)

To protect the Refund availability, the protocol enforces a strict Liveness Check on pulose posting: If the Oracle attempts to post a pulse when there are less than 50 slots (~20s) remaining before the reveal_deadline_slot, the transaction is rejected with PulseTooLate.

This guarantees that: 1. If a pulse is accepted, users always have at least ~20s to submit reveals. 2. If the Oracle is too late, the round remains in the "Pulse Not Set" state, ensuring users can claim a Refund after the timeout.

2) Users commit at the boundary slot

The boundary is defined in slots. If a commit lands at exactly commit_deadline_slot, it is still within the window.

  • If a reveal lands after reveal_deadline_slot, it is rejected (the ticket becomes NO-REVEAL).

3) Slot-time vs wall-clock time

Slots are the only timing source the program can rely on. User-facing tooling may display approximate wall-clock times, but correctness must be enforced using slots.


Deployment phases: Devnet vs Mainnet

  • Devnet: Used for end-to-end testing and UI/UX validation. Operator automation may be more permissive.
  • Mainnet: Requires hardened oracle operations, rate limiting, and stricter monitoring.

Gasless UX: the relayer role (TBD)

The protocol supports “gasless” variants where:

  • users sign messages (ed25519) instead of transactions
  • a relayer pays fees and submits the on-chain transaction

Current status:

  • Gasless commit: Implemented via commit_batch_signed.
  • Gasless reveal: Implemented via reveal_batch_signed.
  • State: Operational details (spam prevention, per-user quotas) are still to be defined.
  • Goal: Users should only need the stake token to participate.

For devnet/localnet demos:

  • Choose commit/reveal windows with enough slots to absorb normal network variance.
  • Prefer conservative spacing: commit closes well before the targeted pulse can be knowable.
  • Keep claim_grace_slots long enough for users in different time zones.

Exact numbers are deployment- and network-dependent, so the docs avoid hardcoding constants.