davideandClaude Opus 5 526a649c8b Say what bets and withdrawals actually exclude (B-70)
The flowchart's WITHDRAW node (E1) stated that a withdrawal cannot happen
together with a bet in progress. The code only serializes the two *builds*
through the per-user lock: a withdrawal is accepted while a bet is still
unconfirmed, as long as confirmed, unspent UTXOs cover it.

CLAUDE.md makes every node of the diagrams binding, so one of the two had
to move, and it is the diagram. The hazard the node was reaching for is
the two transactions picking the same UTXO, and that is already excluded
twice: app/tx/locks.py keeps the builds from overlapping, and select_utxos
skips anything already marked spent_txid. What the node forbade on top of
that is spending untouched, confirmed money — so implementing it as
written would freeze a user's whole balance for a block after every bet
and protect nothing. E1 now describes the real rule, and CLAUDE.md's
per-user-lock paragraph states it is the only exclusion between the two.

Regenerated the A4/A3 PDFs (gitignored, so not in this commit).

The regression test is behavioural, not a wording check: it funds a user
with two confirmed UTXOs, bets (taking the larger), and asserts the
withdrawal goes through on the other one with the bet still unconfirmed
and neither transaction spending the other's input. A second test keeps
the diagram from drifting back.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 16:16:13 +02:00
2026-07-21 11:14:56 +02:00

PLM Lottery

A periodic-round lottery system built on PLM, a Bitcoin-like coin (mainnet). Each user gets a dedicated server-derived P2WPKH address; they deposit PLM to that address, place a fixed-cost bet to enter the current round, and when the round closes a winner is drawn who receives 70% of the prize pool (the remaining 30% goes to fees).

This is a custodial system: private keys are generated and held server-side, encrypted at rest. See CLAUDE.md for the full architecture, domain decisions, and known gaps before treating this as production-ready.

Quick start

The server always runs via Docker (app + Caddy reverse proxy with automatic TLS) — in dev and production alike, with only SITE_ADDRESS differing between the two. There's no supported way to run uvicorn directly; the venv is only for local tooling (tests, Alembic migrations, the one-time key scripts) — see CLAUDE.md.

cp .env.example .env               # then fill in the generated secrets, see docs/setup.md
mkdir -p data/db data/keys data/logs
docker compose run --rm app python scripts/generate_master_key.py
docker compose up -d --build

Open https://localhost/ for the test UI, https://localhost/admin for the admin dashboard (a self-signed-certificate warning on first visit is expected in dev — accept it, or use curl -k). The interactive API docs at /docs are disabled by default (they'd otherwise expose the whole API surface, admin endpoints included) — set ENABLE_API_DOCS=true in .env to enable them.

See docs/setup.md and docs/running-the-server.md for the full walkthrough (secrets, master key generation, production TLS with a real domain).

Documentation

Tech stack

Python (FastAPI, SQLAlchemy async + Alembic, Argon2 + JWT auth), Electrum protocol for PLM network access (no full node), Docker + Caddy for deployment. See CLAUDE.md for the complete list and the reasoning behind each choice.

Testing

python -m pytest                    # all tests
python -m pytest tests/unit/test_hd.py   # one file

351 unit tests cover HD derivation, PSBT building, the Electrum client, bets, deposits, withdrawals, the round/draw engine, RBF fee-bumping, admin config, the pending-inclusive balance calculation, and the SSE push channel. No automated integration tests against a live Electrum connection — mainnet verification so far has been manual (see CLAUDE.md's "Project status").

S
Description
No description provided
Readme
2.2 MiB
Languages
Python 72.5%
JavaScript 17.7%
CSS 4.2%
HTML 3.8%
Shell 0.8%
Other 0.9%