# FLOW.md — как ходят данные: кто, кому и в какой момент (sequence-диаграммы) **Репо:** `pump-game-ops` (мета-репо, документация). **Статус:** живой, дополняется. Цель — раз и навсегда зафиксировать **порядок обмена сообщениями** между участниками (фронт, бэкенд/релейер, контракт, RFС Solana, кошелёк, pump.fun), чтобы было понятно «кто кому что шлёт и в какой момент», включая тонкость **согласия игрока (подписи)**. Легенда участников: - **Клиент (браузер / Unity WebGL)** — UI игрока. - **Phantom** — браузерный кошелёк (держит приватный ключ игрока; **согласие = подпись**). - **Бэкенд (релейер)** — наш сервер: строит/ретраслит ставки, держит ваулт-фандинг. - **Контракт** — `smart-updown-token` на цепочке Solana (ваулт фантиков, create/close bet). - **RPC Solana** — узел цепочки (localnet `192.168.76.199:8890`, на бою — публичный). - **pump.fun** — меняльная лавка (на бою; SOL↔фантики по живому курсу). --- ## 1. КАК ЭТО РАБОТАЕТ СЕЙЧАС (localnet, тестовый пульт, БЕЗ pump.fun и без Phantom) > Текущее состояние (см. `test-front`, `smart-updown-token/relayer`). Ставка подписывается > **сервером** (custodial-кошелёк шлюза), кошелёк игрока в подписи НЕ участвует. > Фантики и SOL **накинуты вручную** (тест), обменника нет. ```mermaid sequenceDiagram participant U as Игрок (браузер) participant F as Пульт (test-front) participant G as HTTP-шлюз gateway.ts participant S as Контракт (localnet) participant R as RPC Solana (8890) U->>F: открыть страницу, «Обновить state» F->>G: GET /state G->>S: readGlobal() S-->>G: min/max/expiry/vault/counter G-->>F: JSON (лимиты, vault) F-->>U: показать лимиты/ваулт U->>F: «Проверить баланс» (адрес) F->>G: GET /balance/{address} G->>R: getBalance, getTokenAccountBalance (ATA) R-->>G: SOL + фантики G-->>F: {sol, tokenHuman} F-->>U: «Фантики: N, SOL: M» U->>F: «Сделать ставку» (сумма, сторона) F->>G: POST /bet {side, amountUnits, address?} G->>S: createBet (подпись КЛЮЧОМ ШЛЮЗА) S-->>G: tx (в сеть) G-->>F: {id, bettor, tx} F-->>U: «Ставка id=X ушла» Note over U,G: пауза ~15с (expiry) — контракт не даёт закрыть раньше U->>F: «Закрыть ставку» (id) F->>G: POST /close {id} G->>S: closeBet (по текущей цене, подпись шлюза) S-->>G: исход (payout_done / house_won) G-->>F: {statusName, exitPrice} F-->>U: «выиграл» / «дом выиграл» ``` **Кто подписывает согласие игрока?** В этом режиме — **никто из игрока**. Согласие даётся **нажатием кнопки** в пульте; подписывает **сервер (custodial-ключ шлюза)**. Настоящего вывода/пополнения нет — балансы накинуты. --- ## 2. КАК ЭТО ДОЛЖНО РАБОТАТЬ ПО-НАСТОЯЩЕМУ (боевой, pump.fun + Phantom + подпись игрока) > Целевая архитектура (фазы devnet→mainnet). Здесь **согласие игрока = подпись в Phantom**, > а обмен делается через **pump.fun** по живому курсу. ```mermaid sequenceDiagram participant U as Игрок participant F as Фронт (Unity/WebGL) participant P as Phantom (кошелёк) participant B as Бэкенд (релейер) participant S as Контракт (фантики) participant R as RPC Solana participant PF as pump.fun (лавка) %% --- ПОПОЛНЕНИЕ: SOL -> фантики --- U->>F: «Пополнить» (SOL) F->>P: запросить подпись swap (акис consent) P-->>U: «Согласен(на) на обмен?» U-->>P: ОК P-->>F: подписанная swap-транзакция F->>B: POST /api/pump/swap (подпись) B->>PF: swap SOL→фантики (живой курс) PF->>R: обработать swap R-->>B: фантики на ATA игрока B-->>F: ok F-->>U: «Баланс +N фантиков» %% --- СТАВКА --- U->>F: «Поставить» (сумма, сторона) F->>P: построить createBet, запросить подпись P-->>U: «Подтвердить ставку?» U-->>P: ОК (согласие) P-->>F: подписанная createBet F->>B: POST /api/bet (ретрансляция) B->>R: sendRawTransaction (ваулт→контракт) R-->>B: tx принята B-->>F: {id, status} F-->>U: «Ставка ушла, ждём исход» %% --- ВЫВОД: фантики -> SOL --- U->>F: «Вывести» (фантики) F->>P: запросить подпись swap P-->>U: «Согласен(на) на обмен?» U-->>P: ОК P-->>F: подписанный swap F->>B: POST /api/pump/swap (обратный) B->>PF: swap фантики→SOL (живой курс) PF->>R: обработать R-->>B: SOL на кошелёк игрока B-->>F: ok F-->>U: «Баланс -N фантиков, +SOL» ``` **Главное отличие от текущего:** в бою **согласие игрока** — это **криптографическая подпись в Phantom** на каждое действие с деньгами (пополнение, ставка, вывод). Сервер **никогда не видит приватный ключ игрока** — только подписанную транзакцию, которую ретранслирует в сеть. Пульт без Phantom (раздел 1) — только для гонки механики на localnet. --- ## 3. Сравнение «сейчас» vs «боевой» | Аспект | Сейчас (localnet) | Боевой (devnet→mainnet) | |---|---|---| | Согласие игрока | кнопка пульта | **подпись в Phantom** | | Кто подписывает ставку | сервер (custodial ключ шлюза) | **игрок (Phantom)** | | Пополнение/вывод | нет (балансы накинуты) | **swap через pump.fun** по живому курсу | | Сеть | localnet (192.168.76.199:8890) | devnet→mainnet (реальная Solana) | | Валюта | тестовые фантики (накинуты) | REAL фантики за реальный SOL | | Приватный ключ | на сервере (custodial) | **только в Phantom игрока** | --- ## 4. Опорные репозитории/файлы - Пульт без Phantom: `subochev/test-front` → `index.html` (дёргает шлюз по `/api/...`). - HTTP-шлюз: `subochev/smart-updown-token` → `relayer/src/gateway.ts` (`/state`, `/balance/{address}`, `/bet`, `/close`, `/faucet/{address}` — последний только localnet). - Релейер (серверный казначей): там же → `relayer/`. - Бэкенд-свап-клиент pump.fun: `subochev/smart-updown-server` → `src/main/kotlin/.../PumpApiClient.kt`, `PumpApiController.kt` (`/api/pump/swap`). - Публика: `deploy/flows` (этот файл).