Зафиксировано разделение: ручка тестовая по назначению (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, релейер — точка доверия.