Проверено на smart-updown-server: GameService.submitBet не сверяет
payload.entryPrice со своим priceSource, сравнение JSON-подсказки с tx
лишь логирует log.warn и не отклоняет. Клиент подписывает entry_price сам.
Зафиксирована инверсия: custodia-шлюз стенда эту дыру закрывает (цена из
NATS на сервере), а неcustodial прод-бэкенд открыт. Переход на неcustodial
без серверной сверки entry_price ухудшит положение.
Зафиксировано разделение: ручка тестовая по назначению (faucet-TASK.md) и на
проде не нужна, однако проверка сети в коде отсутствует, а дефолт
SMART_ALLOW_AIRDROP='1' (config.ts) — открыт. Значит 'не нужна' держится
памятью деплойщика, а не кодом. Фикс: дефолт '0' + getGenesisHash() в handleFaucet.
Разделены два механизма ручки /faucet:
(а) SOL-налив (requestAirdrop) — технически только localnet, mainnet-RPC
отдаёт 410 (проверено вживую);
(б) налив фантиков (mintTo) — НЕ привязан к сети, гейт только конфиг-флаг
SMART_ALLOW_AIRDROP, проверки кластера в коде нет;
SOL-барьер обходится: при балансе >=2 SOL airdrop не зовётся (ops.ts:204)
и выполнение доходит прямо до mintTo.
Отмечено, что на боевом мемкойне pump.fun (revoked mint authority) часть (б)
исчезает сама.
15 пунктов, отмечаются [ ]/[x]. Критичное найдено воспроизведением на
testfront.binom.pw, не чтением кода:
- close_bet проверяет только нижнюю границу окна (now >= expire_time) —
верхней нет, ставка висит open бесконечно, момент расчёта выбирает
вызывающий /close;
- в шлюзе нет авто-закрытия (единственный setInterval — WS-heartbeat);
- /bet, /close, /faucet открыты наружу без авторизации; faucet выдал
5 SOL + 10000 фантиков при SMART_ALLOW_AIRDROP=1 в боевом поде;
- эксплойт воспроизведён: ставка DOWN (entry=9998000000) висела open >2 мин
после экспирации 15с и закрыта при exitPrice=9997000000 -> payout_done.
Плюс: множитель 1.3x требует 77% винрейта, запертые средства в ваулте,
равные цены не финализируют ставку, NATS без auth, релейер — точка доверия.
ADR-007 (выбор источника binance-market/NATS) пришёл из другой сессии —
оставлен как есть, с апдейт-сноской. Реализация зафиксирована отдельным
ADR-008: NATS-консьюмер в шлюзе, цена x1e8 строковым парсером, раздача
фронту по WebSocket, деплой в k3s на testfront.binom.pw.
- README: новая секция «Внешние зависимости» — binance-market как общий
инфраструктурный upstream, а не часть игры (~/common-projects/invest/binance-market,
контракт: NATS market.price.solusdt или WS /ws/price).
- docs/DECISIONS: добавлен ADR-007 с обоснованием; ADR-006 получил апдейт-сноску.
- docs/ECONOMY: «Курс и балансы» — указано, откуда берётся реальная цена SOL.
- TASKS: задачи «Цена SOL: реальный источник» (Фаза 0) и «PriceSource: реальная
цена» (Фаза 2) переведены из TODO в IN_PROGRESS, со ссылкой на ADR-007 и
binance-market; test-front задача тоже помечена.