Initial commit
This commit is contained in:
@@ -0,0 +1,67 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Language
|
||||||
|
|
||||||
|
The user communicates in Italian in chat — reply to them in Italian. Everything written to the repository (code, comments, commit messages, docs, this file) must be in English. Reasoning/thinking should also be done in English.
|
||||||
|
|
||||||
|
## Project status
|
||||||
|
|
||||||
|
This repository is at the **specification stage, not yet implemented**: it currently contains only [flowchart.mmd](flowchart.mmd), which is the source of truth for the project and describes the entire application flow. The tech stack is decided (see below) but no code, build system, or lint/test commands exist yet — once the project is scaffolded, this section must be updated with real commands (install, run, lint, test — including how to run a single test).
|
||||||
|
|
||||||
|
Before writing code, always read [flowchart.mmd](flowchart.mmd) in full: every node in the diagram corresponds to a behavior that must be implemented exactly as described, including the labels on the edges (conditions, retries, loops).
|
||||||
|
|
||||||
|
## Tech stack (MVP)
|
||||||
|
|
||||||
|
- **Backend language**: Python.
|
||||||
|
- **PLM node access**: Electrum protocol only (no full node/P2P). Bootstrap server for development: `santantonio.sytes.net:50002` (SSL).
|
||||||
|
- **Auth**: Argon2 password hashing + JWT sessions.
|
||||||
|
- **Secrets**: master xprv encrypted at rest with a symmetric scheme (AES-GCM/Fernet); the encryption key itself lives in an env var, never in the DB or in git.
|
||||||
|
- **Operational config** (fee/commission address, RBF fee-bump wallet, etc.): stored in a DB config table, not env vars — must be editable without a redeploy.
|
||||||
|
- **Round duration**: configurable via env var, default 10 minutes (not hardcoded).
|
||||||
|
|
||||||
|
## PLM network parameters
|
||||||
|
|
||||||
|
Source of truth: `PalladiumWallet` repo, [ChainProfiles.cs](../PalladiumWallet/src/Core/Chain/ChainProfiles.cs) and [PalladiumNetworks.cs](../PalladiumWallet/src/Core/Chain/PalladiumNetworks.cs) — always re-check that repo if a value is needed that isn't listed here, rather than guessing.
|
||||||
|
|
||||||
|
Mainnet:
|
||||||
|
- BIP44/84 coin type: `746` (i.e. HD path `m/84'/746'/0'/0/index`)
|
||||||
|
- Bech32 HRP: `plm`
|
||||||
|
- P2PKH address version byte: `55` (addresses start with `P`)
|
||||||
|
- P2SH address version byte: `5`
|
||||||
|
- WIF prefix: `0x80`
|
||||||
|
- Block time: 120s
|
||||||
|
- BIP32 extended key headers (Legacy/native-segwit `zprv`/`zpub` etc.): see `ExtKeyHeaders` in `ChainProfiles.cs`
|
||||||
|
|
||||||
|
## MVP business parameters
|
||||||
|
|
||||||
|
- Fixed bet cost: **10 PLM** per round.
|
||||||
|
- Prize split: 70% winner / 30% fees (fee address configurable in DB).
|
||||||
|
- Minimum deposit/withdrawal amount: **1 PLM** (business-friendly floor, above the network's technical dust limit).
|
||||||
|
- Confirmations required for all tx types (deposit, bet, payout, withdrawal): **1**.
|
||||||
|
|
||||||
|
## What is PLM Lottery
|
||||||
|
|
||||||
|
A periodic-round lottery system built on a Bitcoin-like coin (PLM, mainnet). Each user gets a dedicated P2WPKH address (server-side HD wallet); 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).
|
||||||
|
|
||||||
|
## Architecture (from the flowchart subgraphs)
|
||||||
|
|
||||||
|
The flow is organized into 5 phases, each a subgraph in [flowchart.mmd](flowchart.mmd):
|
||||||
|
|
||||||
|
- **REG (Registration)**: on signup the server derives a new P2WPKH address via BIP84 (`m/84'/coin'/0'/0/index`, one index per user) from a master xprv **encrypted at rest**. This address is permanent and serves as both the deposit address and the address that receives winnings and withdrawals.
|
||||||
|
- **DEP (Balance top-up)**: an ElectrumClient/SPV subscribes to the user's address scripthash. Internal balance (DB) is credited after **1 confirmation only** — the reorg risk at 1-conf is knowingly accepted in v1, with no rollback logic.
|
||||||
|
- **PLAY (Bet)**: fixed cost per round, **at most one active bet per user at a time** in v1. The server builds a PSBT user-address → pool-address for the fixed amount, with a **change output back to the same user address** (the user's balance must never exactly equal the bet amount). Fee minimized (~1 sat/vB), **deducted from the bet amount**. If the tx doesn't confirm within a timeout, fee-bump (RBF) and rebroadcast.
|
||||||
|
- **DRAW (Periodic draw)**: configurable timer (default 10 minutes). Round closing **waits for all already-broadcast bets to confirm** before proceeding (avoids losing bets at the round boundary). The **next round only opens once the previous round's payout tx is confirmed** — rounds never overlap in v1. v1 draw algorithm (deliberately simple, meant to be replaced later): wait for the first block confirmed after round closing, use its hash as seed, `index = seed mod participant_count` over the participant list ordered by **broadcast timestamp** (this is also the tie-break when two bets confirm in the same block). Every participant has **equal probability regardless of bet amount** (consistent with the fixed bet amount). The payout (70% winner / 30% fees) is signed with the pool address key; the **payout fee is deducted from the winner's 70%**, the 30% fee share stays intact. Same timeout → RBF → rebroadcast pattern here too.
|
||||||
|
- **WITHDRAW (Withdrawal)**: the only way to move funds out of the platform to an external address. PSBT user-address → external-address + change back to the user address, fee deducted from the withdrawn amount, same RBF retry pattern.
|
||||||
|
|
||||||
|
PLAY and WITHDRAW share a **per-user DB lock**: a user can never have a bet-build and a withdrawal-build in flight at the same time, since both would otherwise spend from the same UTXO set on the user's dedicated address.
|
||||||
|
|
||||||
|
## Non-obvious domain decisions
|
||||||
|
|
||||||
|
These choices were made explicitly during design (not derivable from reading a single file) and must be respected in any implementation:
|
||||||
|
|
||||||
|
- Private keys (xprv) are generated and held **server-side** — this is not a non-custodial system: the user never controls their own keys until they make an explicit withdrawal.
|
||||||
|
- The user's personal deposit address always doubles as the winnings-receiving address: there is no separate "winner address".
|
||||||
|
- 1 confirmation is the chosen threshold for all tx types (deposits, bets, payouts, withdrawals): don't introduce different thresholds (e.g. 3 or 6 confirmations) without an explicit decision.
|
||||||
|
- The draw algorithm (node R) is deliberately simple and should be treated as a replaceable/pluggable component, not the final design — don't architect around its current implementation.
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
flowchart TD
|
||||||
|
|
||||||
|
subgraph REG["Registration"]
|
||||||
|
A["User registers: username + password"] --> B["Server derives a new P2WPKH address\n(BIP84, path m/84'/746'/0'/0/index)\nmaster xprv encrypted at rest"]
|
||||||
|
B --> C["Address linked to the user profile in the DB"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph DEP["Balance top-up"]
|
||||||
|
C --> D["User sends PLM to their dedicated address"]
|
||||||
|
D --> E["ElectrumClient/SPV monitors the address\n(subscribe scripthash)"]
|
||||||
|
E --> F{"Tx confirmed\n(1 confirmation)?"}
|
||||||
|
F -- No --> E
|
||||||
|
F -- Yes --> G["User balance credited in the DB\n(balance = confirmed UTXOs on the address)"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph PLAY["Bet"]
|
||||||
|
G --> H{"User confirms bet purchase?\n(fixed cost: 10 PLM per round,\nmax 1 active bet at a time,\nacquires per-user DB lock shared with WITHDRAW)"}
|
||||||
|
H -- No --> G
|
||||||
|
H -- "Yes (balance >= bet cost)" --> I["Server builds PSBT:\nuser address -> pool address\n(bet cost) + change -> user address\nfee ~1 sat/vB deducted from the bet amount"]
|
||||||
|
I --> J["Server signs with the user's derived key"]
|
||||||
|
J --> K["Broadcast tx to the network"]
|
||||||
|
K --> L{"Tx confirmed\n(1 confirmation)?"}
|
||||||
|
L -- "No (timeout)" --> K2["Fee bump (RBF) and rebroadcast"]
|
||||||
|
K2 --> K
|
||||||
|
L -- Yes --> M["User registered as a participant\nin the current round (with bet amount)"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph DRAW["Periodic draw"]
|
||||||
|
N["Round timer: every X minutes (configurable, default 10)"] --> O{"Are there bets\nalready broadcast but not yet confirmed?"}
|
||||||
|
O -- Yes --> O
|
||||||
|
O -- No --> O2["Close current round"]
|
||||||
|
O2 --> P["List of round participants\n(user address + bet amount),\nordered by broadcast timestamp\n(tie-break for same-block confirmations)"]
|
||||||
|
P --> Q{"Are there participants?"}
|
||||||
|
Q -- No --> N
|
||||||
|
Q -- Yes --> R["Draw winner (simple v1 algorithm):\n1. wait for the first block confirmed after round closing\n2. seed = block hash (hex -> integer)\n3. index = seed mod participant_count\n4. winner = participants[index]\n(anyone can recompute and verify it;\nalgorithm replaceable in the future)"]
|
||||||
|
R --> S["Compute total round prize pool\n(sum of confirmed deposits to the pool address)"]
|
||||||
|
S --> T["70% of the prize pool - payout tx fee\n-> winner's deposit address"]
|
||||||
|
S --> U["30% of the prize pool (unchanged)\n-> fee address (configurable)"]
|
||||||
|
T --> V["Payout tx signed with\nthe pool address key"]
|
||||||
|
U --> V
|
||||||
|
V --> V2{"Tx confirmed\n(1 confirmation)?"}
|
||||||
|
V2 -- "No (timeout)" --> V3["Fee bump (RBF) and rebroadcast"]
|
||||||
|
V3 --> V2
|
||||||
|
V2 -- Yes --> W["Log round\n(winner, amount, txid) for audit"]
|
||||||
|
W --> N
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph WITHDRAW["Withdrawal (simple v1)"]
|
||||||
|
G --> X["User requests withdrawal:\nexternal address + amount <= balance\n(min 1 PLM, acquires per-user DB lock\nshared with PLAY)"]
|
||||||
|
X --> Y["Server builds and signs PSBT:\nuser address -> external address\n+ optional change -> user address\nfee deducted from the withdrawn amount"]
|
||||||
|
Y --> Z["Broadcast + wait for 1 confirmation\n(same RBF-on-timeout pattern)"]
|
||||||
|
Z --> G
|
||||||
|
end
|
||||||
|
|
||||||
|
M --> N
|
||||||
Reference in New Issue
Block a user