Skip to content

keeganthomp/lightly

Repository files navigation

Lightly

Texas Hold'em on Solana. USDC settlement. VRF-audited shuffles. Monorepo with a lean Anchor program, Hono+Bun API, Vite+React client, and Drizzle-backed off-chain state.

Layout

apps/
  api/       Hono + Bun server (WS + hand engine + settlement worker)
  web/       Vite + React client (wallet-adapter, smooth animated felt)
packages/
  idl/       Hand-rolled Anchor IDL helpers (discriminators, PDAs, borsh, ix builders)
  db/        Drizzle schema + migrations
  shared/    Cards, VRF-seeded shuffle, 7-card evaluator, wire protocol
programs/
  poker/     Anchor program (Rust) + LiteSVM TS tests

Program

7 instructions, all privileged ones guarded by has_one = operator:

ix signer purpose
initialize_table operator Create table PDA + vault ATA
buy_in player Deposit USDC → seat balance
cash_out player Withdraw from unlocked seat
begin_hand operator Lock N seats for a monotonic hand_id
settle_hand operator Atomic payout; asserts sum(debits) == sum(credits) + rake; creates SettlementReceipt PDA (replay-safe via init)
emergency_timeout_refund player Unilateral refund if operator leaves a seat locked past dispute_window_slots
withdraw_rake operator Sweep accrued rake to treasury ATA

Custody model: semi-custodial. Operator has settle authority; players always have the unilateral refund backstop.

Tests

20/20 LiteSVM tests in programs/poker/tests/poker.test.ts. Run:

bun install
cd programs/poker/tests && bun test

Covers every instruction's happy path, attack paths (wrong signer, replay, locked-seat cash_out, rake cap, pot math), and the conservation invariant across 5 hands.

Local dev (end-to-end on real chain)

Prereqs

  • solana CLI 3.x (ships cargo-build-sbf, solana-test-validator, solana-keygen)
  • bun ≥ 1.2

1. Build the program

cargo-build-sbf
# artifact: target/deploy/poker.so
# program id: 9FeibPV2hjbkcu4YHSnUMr9ikWV7QLWMmBpVFZAcYsZH

2. Start a local validator

Surfpool 0.1 has a narrow RPC subset. For a real dev loop use the Solana test validator:

solana-test-validator --reset \
  --bpf-program 9FeibPV2hjbkcu4YHSnUMr9ikWV7QLWMmBpVFZAcYsZH target/deploy/poker.so
# RPC: http://127.0.0.1:8899

(When surfpool supports --bpf-program + full RPC it will be the preferred option — see Surfpool.toml placeholder.)

3. Bootstrap a mint + table

bun run scripts/bootstrap.ts
# Airdrops SOL to the operator keypair, creates a dev-USDC mint,
# initializes table id=1, and prints the env vars you need.

Copy the printed env vars into apps/api/.env and apps/web/.env.

To fund a specific wallet (e.g. your Phantom):

bun run scripts/bootstrap.ts --player=<your-wallet-pubkey> --amount=1000

4. Run the API + UI

bun install
bun --filter @lightly/api dev      # API on :4000 — now submits begin_hand + settle_hand
bun --filter @lightly/web dev      # Vite on :5173

Open http://localhost:5173 → connect Phantom → sign the SIWS challenge → use the Deposit button to buy in → click Start hand → play.

On hand end, settle_hand lands on-chain. You'll see the tx sig in the API logs and your seat balance updates.

Security notes

  • overflow-checks = true in release profile + checked_add/checked_sub on every money line.
  • Account<'info, T> everywhere — Anchor enforces owner = program ID.
  • Interface<'info, TokenInterface> pins the token program for CPIs.
  • init on SettlementReceipt makes replay impossible: two settlements for the same hand_id collide on PDA init.
  • Monotonic hand_id prevents stale settle + rebegin.
  • Time-based expiry uses slots, not wall clock.
  • Mints with transfer_hook / confidential transfers / frozen-default are rejected by spec — stick to classic USDC/USDT for MVP.

Fairness

  • Dealer draws a 32-byte seed per hand (dev: crypto.getRandomValues; prod: ORAO VRF).
  • sha256(seed) is published as a commitment before any card is dealt (shown in UI).
  • On showdown the seed is revealed; clients can re-derive the deck via shuffleDeck(seed) from @lightly/shared.

Roadmap to real launch

  • Replace dev seed with ORAO VRF on-chain call.
  • Wire settlement worker to submit begin_hand + settle_hand via Helius Sender (Jito-bundled for frontrun protection).
  • Swap operator authority to a Squads v4 multisig.
  • LaserStream subscription on program ID → reconcile HandSettled events into settlements table.
  • Helius webhook on vault ATA → reconcile buy-in/cash-out into ledger.
  • MagicBlock ephemeral rollup for sub-slot action latency on high-volume tables.

See the research reports for the full 2026 stack rationale.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors