Приёмка и починка 15.09.2026: - ADR-009: один бэк на оба домена — прод-домен smart-updown.binom.pw переведён на тот же TS-шлюз (:8895), что и testfront; Kotlin-бэк (3NWEK) выключен обратимо. Разобраны расхождения API игры и шлюза (их должны править во фронте). - ADR-010: две ловушки деплоя фронта — (1) чарт рендерит только path '/', поэтому helm-релиз сносит /api,/ws → вынесены в отдельный ingress smart-updown-api вне helm; (2) захардкоженный values.image.tag бьёт Chart.AppVersion → helm upgrade НЕ поднимает новый образ (новый RS не создаётся), на домене остаётся старый билд при 'Upgrade complete'. Приведена правильная команда (--reuse-values --set image.tag=<N>) и способ ПРОВЕРКИ по кубу и домену, а не по helm. Отмечен остаточный риск: Unity-ассеты immutable 7 суток при неизменяемых именах файлов → кэш браузера держит старый билд. - README: карта деплоя (кто где живёт), статус проекта на 15.09, актуализирован блок безопасности (SEC-16 — утечка SOL, блокер перед mainnet), Kotlin-бэк помечен выключенным, добавлен TS-шлюз как боевой бэк, ссылки на tools/ и k8s/. - TASKS.md: деплой-памятка фронта + задачи фронтендеру (убрать image.tag, хэш в именах ассетов, привести API игры к контракту шлюза).
14 KiB
TASKS.md — список задач (трекер проекта)
Здесь живёт весь список задач — не только мои. Трекаем проект целиком. Бинарные составляющие:
- фаркул/pivotable-задачи (что можно отложить или развернуть иначе) помечаются
[pivotable]; - общие/инфра (деплой, стабильность, мок) —
[pump.meta].
Статусы: TODO / IN_PROGRESS / DONE / BLOCKED.
⭐ Актуальное состояние (2026-09-13)
Где мы: цена SOL — реальная, из NATS, шлюз и тестовый фронт крутятся в k3s на
testfront.binom.pw. Первый щуп экономики закрыт: ставка → раунд → результат считается
по живой рыночной цене.
Новое (2026-09-13):
- Цена SOL берётся из NATS (
market.price.solusdt), заглушка удалена — ADR-007, детали вdocs/PRICE-NATS.md. - Шлюз раздаёт цену фронту по WebSocket:
wss://testfront.binom.pw/api/ws. test-frontпоказывает живую цену SOL.- Оба контейнера (статика + шлюз) — в k3s, ns
game, один домен через ингресс. - Solana localnet пересобрана с нуля, контракт задеплоен (
9ALs…).
⭐ Предыдущее состояние (2026-09-09)
Где мы: Фаза 1 (контракт переведён на фантики) — DONE. Сейчас вход в Фазу 2 (релейер под токен).
Готово:
- Контракт
smart-updown-token— переведён на SPL-токен (фантики), IDL+тесты обновлены. Коммит45d64d4. - Ktor swap-клиент в бэкенде (ввод/вывод) — заготовка.
- Тестовый фронт
test-front— каркас (Phantom, балансы, пополнение/вывод).
В работе / вперёд:
- Фаза 2 (активная): релейер перевести с SOL на токен (ops/pda/config). После неё + E2E на localnet.
- Веха «первый щуп»: 👉 как только релейер на фантиках + E2E на localnet прогнаны — через
test-frontвы самостоятельно щупаете: пополнить фантики → ставка → результат. Это первый реальный user-тест (без Unity).
Параллельные TODO (не блокируют Фазу 2): реальная цена (вместо RandomPriceSource — источник выбран: binance-market, ADR-007, остаётся интеграция), эмиссия, ликвидность/комиссии swap.
Фаза 0 — Экономика и спека (кросс)
- TODO ADR-002 зафиксирован, документировать
ECONOMY.md: токен, курс (Способ 1), decimals=6, mint-адреса —[pump.meta] - DONE Решить «вверх/вниз» — предмет ставки = цена SOL (ADR-006), валюта = фантики
- DONE Цена SOL: реальный источник (ADR-007) —
subochev/binance-marketчерез NATSmarket.price.solusdt; интеграцияPriceSourceв релейере сделана (ADR-008, 2026-09-13) - TODO Кто держит ликвидность swap и комиссии —
[pump.meta] - TODO Эмиссия: разовая vs постоянная —
[pump.meta]
Фаза 1 — Контракт на токене (ядро) — репо smart-updown-token (копия Smart-game)
- DONE Создана копия контракта
smart-updown-token(ветка main, чистый) — работаем тут - DONE Перевести
create_betс SOL (lamports) на SPL-токен: приём фантиков с ATA игрока на ваулт - DONE Выплата в
close_betфантиками из ATA-ваулта на ATA игрока - DONE
state/constants: единицы = token units (decimals=6), + VAULT_SEED - DONE Обновить IDL (idl/ + relayer/idl/) + Anchor-тесты (10/10) — коммит 45d64d4
- DONE Localnet стенд поднят заново (ledger пересобран), контракт задеплоен, mint создан,
initпрогнан (2026-09-13) - DONE E2E живьём: ставка → close по реальной цене из NATS (
entryPrice=10195000000при курсе 101.95)
Фаза 2 — Релейер и цена (АКТИВНАЯ — следующий шаг)
- IN_PROGRESS SolanaClient/ops: подписывать/отправлять токеновую ставку (ATA + ваулт) — перевести релейер с SOL на токен
- TODO readGlobal: баланс vault_token вместо SOL; ensureVaultFunded — наливать токен в vault
- DONE PriceSource: реальная цена (вместо
RandomPriceSource) — интеграция сbinance-market(ADR-007), NATS-консьюмерmarket.price.solusdtвsrc/natsPrice.ts, цена ×1e8 (ADR-008) - TODO Интеграционный тест релейера на токеновом флоу
Фаза 4 — Бэкенд: задействовать swap
- DONE Ktor
PumpApiClient+POST /agents/swap+ DTO + заготовка (вsmart-updown-server) - TODO Проверить реальный swap на devnet (не мок)
- TODO Обвязать
GameService: ввод/вывод фантиков через swap
Фаза 5 — Фронт (Unity)
- TODO Кнопки «Пополнить»/«Вывести», баланс в фантиках
- TODO SolanaBridge.jslib: подпись токеновой create_bet (ATA игрока в ключах)
- TODO Wallet.cs: баланс в фантиках (ATA + getTokenAccountBalance), CanAfford по токену
Фаза 5b — Тестовый фронт (test-front, для ручной гонки экономики без Unity)
- DONE Каркас: Phantom, балансы (фантики+SOL), swap пополнение/вывод через
/api/pump/swap - DONE Ставка вверх/вниз через контракт с поллингом до SETTLED
- TODO Перевести подпись под токеновую версию контракта (после Фазы 1)
- DONE Реальный провайдер цены вместо RandomPriceSource (за нами) →
binance-marketчерез NATS (ADR-007/ADR-008) - DONE Живая цена SOL по WebSocket (
wss://testfront.binom.pw/api/ws), вывод на странице — релиз 2 - DONE Развернуть / дать постоянный URL —
https://testfront.binom.pw(k3s, nsgame, ингресс; релиз 2)
Фаза 6 — E2E и деплой
- TODO Полный круг на devnet: создать токен → swap ввод → ставка токеном → раунд → вывод
- TODO Обновить
API.md/INTEGRATION.md, развернуть на mainnet - TODO Стабильность: версионировать конфиги, mint-адрес в конфиге
Ссылки
- Решения/экономика:
docs/DECISIONS.md,docs/ECONOMY.md - Карта репозиториев:
README.md
⭐ Добавлено 2026-09-15 — боевой домен и находки приёмки
Где мы: боевой домен smart-updown.binom.pw переведён на тот же TS-шлюз (:8895),
что и testfront.binom.pw (некастодиальный Kotlin-бэк выключен, обратимо). Пути /api,/ws
вынесены в отдельный ingress вне helm — релиз игры их больше не сносит.
Найдено при приёмке живьём:
SEC-16— безвозвратная утечка ренты PDA-аккаунта ставки: 1 559 040 lamports с кошелька игрока за каждую ставку, аккаунт не закрывается никогда. Подробности —docs/SECURITY.md. Вердикт: на тестах терпимо (маскируется краном), перед mainnet — блокер.- Расчёт (выплаты) — корректен 3/3: выигрыш
1.3×, проигрыш0, ничья — возврат залога. - Кран зачисляет на цепь с лагом 8–13 с (шлюз рапортует мгновенно) — отсюда ложный симптом «SOL не обновился».
Деплой-памятка фронта игры (fun-game-front2) — прочитать перед каждым релизом:
helm repo update binom
helm upgrade fun-game-front2 binom/fun-game-front2 -n game \
--reuse-values --set image.tag=<N> --wait --timeout 4m # <N> = тег релиза, НЕ опираться на чарт
⚠️ Без явного --set image.tag образ НЕ обновится: в helm/values.yaml захардкожен image.tag,
он перебивает Chart.AppVersion → спека не меняется, новый под не создаётся, на домене остаётся
старый билд при «Upgrade complete» в helm. Полный разбор — docs/DECISIONS.md (ADR-010).
Проверять по кубу/домену: kubectl get pod -n game -l app.kubernetes.io/name=fun-game-front2 \ -o custom-columns='NAME:.metadata.name,IMAGE:.spec.containers[0].image,CREATED:.metadata.creationTimestamp'.
Задачи фронтендеру (отдать во фронт-репо fun-game-front2):
- Убрать
image.tagизhelm/values.yamlи опираться только наChart.AppVersion(в CI он уже подставляется из тега релиза) — тогдаhelm upgradeперестанет требовать--set. - Хэш содержимого в имени ассетов (
WebGL.<hash>.data/.wasm/.framework.js) на шаге сборки: сейчас nginx отдаёт ассеты какimmutable, max-age=604800при НЕизменяемых именах, поэтому у уже игравших игроков до 7 суток держится старый билд в кэше браузера. - Привести API игры к контракту TS-шлюза (
docs/API шлюза/test-front/API.md): тело ставки{address, side, amountUnits}; поляminAmount/maxAmount— строкой;GET /api/bet/{id}у шлюза отсутствует (см. ADR-009).
Фича на будущее — «ждать, если цена не изменилась» (НЕ ДОДЕЛАНА):
- TODO
[pump.meta]Если по сделанной ставке цена на момент экспирации не изменилась (exit == entry, ничья), нужно подождать ещё 15 секунд и попробовать взять цену заново — чтобы ставка не закрывалась возвратом залога на «плоской» цене, а получала шанс на реальный исход. Суть: ставка не меняется → ждём (не финализируем сразу возвратом). - TODO Вынести окно ожидания в конфиг: сейчас
PRICE_WAIT_TIMEOUT_MS(default15000) отвечает лишь за ожидание первой цены от NATS (relayer/src/priceSource.ts:9) и к ничьей отношения не имеет — нужен отдельный параметр (напр.TIE_WAIT_TIMEOUT_MS) и логика отложенного ретрая вsettle.ts(priceAtOrBefore(expireTime*1000)— сейчас берётся фиксированный момент, ретрай каждые 2 с вечно получит ту же пару, см.SEC-9). - TODO Решить, что делать по истечении окна ожидания: возврат залога (текущее поведение
SEC-9) или иной исход.
Фаза 7 — Цена из NATS и деплой в куб (2026-09-13)
- DONE ADR-007: цена SOL из NATS (
market.price.solusdt), заглушка удалена - DONE
natsPrice.ts— подписка NATS, последняя цена,waitForPrice, ×1e8 строковым парсером - DONE
gateway.ts— WS/ws,GET /price, нормализация/api/...→/... - DONE
test-front— блок «Цена SOL (WebSocket)»: цена, статус, автопереподключение - DONE Dockerfile + helm для шлюза и фронта; деплой в k3s ns
game - DONE Роут
testfront.binom.pwпереведён с 76.199 на куб 76.120 (Traefik VDS) - DONE Релизы:
smart-updown-token7,test-front2 - DONE Документация:
docs/PRICE-NATS.md,docs/diagrams/price-flow.puml, ADR-007 - TODO Пилот: смена
entry_priceна «реальный источник как оракул» до боя (Pyth/Switchboard) - TODO Деградация при отсутствии цены: отдельное решение (бэкфилл/остановка приёма ставок)
Ссылки (дополнено 2026-09-13)
- Цена:
docs/PRICE-NATS.md, диаграммаdocs/diagrams/price-flow.puml - Безопасность:
docs/SECURITY.md— чек-листSEC-1…SEC-15(аудит живого стенда 2026-09-13)