Files
pump-game-ops/docs/DECISIONS.md
T
subochev 30f851fb87 docs: ADR-008 (реализация цены из NATS) + PRICE-NATS.md + PlantUML (фаза 7)
ADR-007 (выбор источника binance-market/NATS) пришёл из другой сессии —
оставлен как есть, с апдейт-сноской. Реализация зафиксирована отдельным
ADR-008: NATS-консьюмер в шлюзе, цена x1e8 строковым парсером, раздача
фронту по WebSocket, деплой в k3s на testfront.binom.pw.
2026-09-13 05:58:05 +03:00

135 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# DECISIONS.md — журнал решений (ADR)
Каждое решение — короткая запись, чтобы потом не гадать, почему всё устроено так.
Формат: дата, статус (принято/рассмотрение/заменено), суть, аргументы за/против, результат.
---
## ADR-001 — Используем свой токен на pump.fun (мемкойн Binary Rocket)
- **Дата:** 2026-09-09
- **Статус:** принято
- **Суть:** выпускаем СВОЙ токен на pump.fun, а не пользуемся чужим.
- **За:** бренд/маркетинг, контроль экономики, стимул игрокам, единая валюта ставок.
- **Против:** надо эмитировать и следить за курсом; чужой токен дал бы меньше работы.
- **Решение:** свой токен. decimals = 6, Token-2022, создание через `create_v2` (по доке pump.fun).
## ADR-002 — Курс живой рыночный (Способ 1)
- **Дата:** 2026-09-09
- **Статус:** принято
- **Суть:** вне игры баланс — в фантиках, курс берётся с рынка (bonding curve/AMM pump.fun).
Ввод = swap SOL→фантики, вывод = swap фантики→SOL. Никакой фикс-привязки/стейблока.
- **За:** нативно pump.fun, привычно игроку-трейдеру, технически проще, маркетинг (рост/падение токена).
- **Против:** баланс «гуляет» с рынком; определённым аудиториям неудобно.
- **Решение:** Способ 1. (Это и диктует, что ставки идут фантиками через контракт.)
## ADR-003 — Ставки идут фантиками через контракт
- **Дата:** 2026-09-09
- **Статус:** принято (вытекает из ADR-002)
- **Суть:** игрок ставит токен, контракт держит фантики в своём ATA-ваулте и платит фантиками.
- **Следствие:** контракт переводится с нативного SOL (lamports) на SPL-токен — это ядро Фазы 1.
- **Против:** трогаем хорошо работающий контракт; но без этого сценарий ввода-игры-вывода не работает.
## ADR-004 — Ввод/вывод через pump.fun swap (`POST /agents/swap`)
- **Дата:** 2026-09-09
- **Статус:** принято
- **Суть:** пополнение = `inputMint: NATIVE_MINT(SOL), outputMint: наш_mint`; вывод = наоборот.
Клиент на бэкенде (Ktor `PumpApiClient`) уже готов в `smart-updown-server`.
- **За:** возвращает готовую подписанную swap-транзакцию, бэкенд не держит ликвидность.
- **Против:** весь ввод/вывод завязан на доступность pump.fun API.
## ADR-05 (идея) — мета-репозиторий для документации и трекинга
- **Дата:** 2026-09-09
- **Статус:** принято
- **Суть:** создать `pump-game-ops`, где живут карта репозиториев, решения, экономика и список задач.
- **За:** единая точка оркестрации, не плаваем по чату. **Против:** риск превратиться во второй трекер.
---
## ADR-005 — Флоу входа/вывода подтверждён (как описал юзер)
- **Дата:** 2026-09-09
- **Статус:** принято
- **Суть:** человек заходит в игру → видит баланс 0 → кнопка «Пополнить» (одна, без выбора) →
swap SOL→фантики → баланс появляется → ставит фантики через контракт (честное списание/начисление
по исходу) → при выходе нажимает «Вывести» → swap фантики→SOL, баланс уменьшается.
- **За:** точный пользовательский сценарий, подтверждённый владельцем; простая UX-модель.
- **Решение:** именно так и работаем — это источник требований для Фазы 1 (контракт на токене) и Фазы 5 (UI).
---
## ADR-006 — Предмет ставки: цена SOL (валюта — фантики)
- **Дата:** 2026-09-09
- **Статус:** принято
- **Суть:** валютой ставки являются наши фантики (токен Binary Rocket), но ставка делается на
**направление цены SOL** (вверх/вниз) — как и в текущей версии игры. Контракт по-прежнему
сравнивает entry/exit_price цены SOL.
- **Цена SOL сейчас** — случайная заглушка (`RandomPriceSource`). Позже заменяется на реальную
(провайдер/оракул). Это отдельная задача, не блокирует Фазу 1 (контракт от способа получения цены не зависит).
**→ Обновление 2026-09-11:** реальный источник выбран — см. ADR-007.
- **Следствие:** фантики = касса/валюта ввода-вывода; контракт оперирует токеном, но исход считает
по цене SOL. Экономика токена (ADR-002 живой курс) не влияет на логику «вверх/вниз».
---
## ADR-007 — Источник цены SOL = upstream-сервис `binance-market`
- **Дата:** 2026-09-11
- **Статус:** принято
- **Суть:** цена SOL для `PriceSource` берётся из уже работающего в инвест-кластере сервиса
`binance-market` (репо `subochev/binance-market`), а не из своей оракуль-логики и не из прямого
опроса Binance. Контракт между игрой и сервисом — публичный:
- **NATS-подписка** на топик `market.price.solusdt` (предпочтительно, в кластере); либо
- **WebSocket** `ws://<binance-market>:8080/ws/price?symbol=solusdt` (fallback / внешние сети).
Источник цены внутри `binance-market` — last-trade (`aggTrade.p` с биржи Binance), тики идут
на каждой сделке → фактически real-time.
- **За:**
- Уже работает и развёрнут в кластере `kube` (ns `invest`), chart `binom/binance-market`,
последний релиз v10. Не надо поднимать ещё один процесс ради цены.
- Есть и NATS, и WS-контракт — обе формы потребления готовы.
- Покрытие `solusdt` уже в списке символов; дополнительных подписок не требуется.
- Цена приходит в тиках сделок (не сэмплинг раз в N секунд) — лучшее разрешение для
сравнения entry/exit в round-based игре.
- Общий сервис инвест-кластера, используется не только этой игрой; его судьба — не наша забота.
- **Против:**
- Один источник (Binance). Если Binance недоступен — игра без цены. Заглушка-fallback
на `RandomPriceSource` остаётся как dev-only.
- Зависимость по латентности от стороннего сервиса. В кластере это несколько мс,
приемлемо.
- **Результат:** задачи «TODO Цена SOL: реальный источник» (Фаза 0) и «PriceSource: реальная цена
(вместо RandomPriceSource)» (Фаза 2) переводятся в `IN_PROGRESS` со ссылкой на это решение.
Никаких новых подписок/оракулов не делаем — только интеграция в релейере (`smart-updown-token`/
`relayer` или `smart-updown-server`). Внешний статус сервиса см. README → «Внешние зависимости».
**→ Обновление 2026-09-13: реализовано, см. ADR-008** (NATS-консьюмер в шлюзе, цена ×1e8,
раздача фронту по WS).
---
## ADR-008 — Реализация: цена SOL из NATS в шлюзе + раздача фронту по WS
- **Дата:** 2026-09-13
- **Статус:** принято, реализовано
- **Контекст:** ADR-006 зафиксировал предмет ставки (цена SOL), ADR-007 выбрал источник
(`binance-market` через NATS). Оставалось реализовать: сама цена была случайной
заглушкой `RandomPriceSource` / `simulated = 100_000_000 + Math.random()`. Исход раунда был
случаен, а не рыночен. При этом в контуре уже работает `binance-market` — сборщик сделок с
Binance, который публикует каждую цену в NATS (`market.price.<symbol>`).
- **Решение:** игровой шлюз (`smart-updown-token/relayer`) подписывается на NATS
(`market.price.solusdt`) и берёт цену оттуда. Заглушка удалена.
- **Транспорт:** core NATS `nats://192.168.88.93:4222`, subject `market.price.solusdt`.
Режим — **только чтение**; `binance-market` не трогаем.
- **Шкала:** строка из NATS переводится в целое ×**1e8** строковым парсером (без float):
`"101.89000000"` → `10189000000`. То же юнит-пространство, что у оракульных цен и у
прежней заглушки (`100_000_000`), поэтому контракт сравнивает цены корректно.
- **Раздача фронту:** шлюз транслирует каждый тик по WebSocket (`/ws`, снаружи
`wss://testfront.binom.pw/api/ws`), сообщение — только цена:
`{"type":"price","symbol":"solusdt","price":"102.30...","ts":...}`.
- **Отсутствие цены:** считается аварийным состоянием и обрабатывается мягко — шлюз
стартует без NATS, запрос цены ждёт таймаут, фронт показывает последнее значение и
переподключается. Отдельный сценарий деградации — тема для будущего решения.
- **За:** исход раунда становится рыночным (entry/exit — реальные цены Binance);
переиспользуется уже работающий сборщик, торговый контур не дублируется; шина отделяет
источник цены от её потребителей (игра, аналитика, будущие сервисы).
- **Против:** появляется зависимость от NATS и от `binance-market`; core NATS не хранит
историю (нет JetStream) — при разрыве подписки цена не «догоняется», нужен живой поток.
- **Альтернативы:** (а) прямая подписка шлюза на Binance WS — дублирование сборщика, лишние
внешние коннекты; (б) оракул on-chain (Pyth/Switchboard) — правильнее для боя, но
дороже и требует фидов; (в) заглушка — отклонено как единственный вариант, оставлена
возможность (`setPriceOverride`) для тестов.
- **Детали и диаграммы:** `docs/PRICE-NATS.md`, `docs/diagrams/price-flow.puml`.