Files
pump-game-ops/tools/check-close-window.sh
T
subochev 6e7132e935 docs(security): SEC-1, SEC-2, SEC-4 закрыты по сути — цена закрытия из истории
Механизм: шлюз берёт цену закрытия из локальной истории на момент expire_time
ставки (priceHistory, node:sqlite, ретеншен 24ч), а не текущую. Момент клика
перестаёт влиять на исход — окно выбора времени закрыто.

Живая проверка (ставка №10, релиз updown-relayer:3):
  цена на момент экспирации 9977000000
  текущая цена в момент клика 9976000000
  exitPrice в транзакции 9977000000  -> взята история, не 'сейчас'
  статус payout_done

Также: tools/ — скрипты проверки (price-history-probe, exploit-decisive,
exploit-check, check-close-window.sh).

Остаток: в контракте верхней границы окна по-прежнему нет (второй слой, не критично);
серверное авто-закрытие — следующая итерация.
2026-09-13 14:47:21 +03:00

81 lines
3.9 KiB
Bash
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.
#!/usr/bin/env bash
# Живая проверка того, что окно выбора времени ЗАКРЫТО.
#
# Схема проверки (повторяет поведение вора):
# 1. создаём кошелёк, пополняем
# 2. ставим ставку
# 3. ЖДЁМ существенно дольше экспирации (по умолчанию 60 с; экспирация 15 с)
# 4. закрываем и смотрим, какую цену вернул шлюз
#
# Ожидание ПОСЛЕ фикса: цена закрытия == цена на момент экспирации (из истории),
# а НЕ текущая цена на момент клика. Плюс шлюз должен отказать, если цена закрытия
# совпала с ценой входа (ставка останется open — это отдельная задача).
#
# Использование: bash check-exploit.sh [секунды_ожидания]
set -uo pipefail
G="${GW_URL:-https://testfront.binom.pw/api}"
WAIT_SEC="${1:-60}"
jqget() { python3 -c "import sys,json;print(json.load(sys.stdin)$1)" 2>/dev/null; }
echo "=== 1. кошелёк ==="
W=$(curl -s --max-time 30 -X POST "$G/wallet" -H 'Content-Type: application/json' -d '{}')
A=$(echo "$W" | jqget "['address']")
echo "address=$A"
[ -z "$A" ] && { echo "ОШИБКА: адрес не получен ($W)"; exit 1; }
echo "=== 2. пополнение ==="
curl -s --max-time 60 "$G/faucet/$A" | head -c 200; echo
echo "=== 3. ставка ==="
BET=$(curl -s --max-time 45 -X POST "$G/bet" -H 'Content-Type: application/json' \
-d "{\"side\":\"UP\",\"amountUnits\":\"100000000\",\"address\":\"$A\"}")
echo "$BET"
ID=$(echo "$BET" | jqget "['id']")
ENTRY=$(echo "$BET" | jqget "['entryPrice']")
[ -z "$ID" ] && { echo "ОШИБКА: ставка не создана"; exit 1; }
echo "id=$ID entryPrice=$ENTRY"
echo
echo "=== 4. цена шлюза СЕЙЧАС (до экспирации) ==="
curl -s --max-time 20 "$G/price"; echo
echo
echo "=== 5. ждём ${WAIT_SEC}с (экспирация 15с — окно прошло) ==="
sleep "$WAIT_SEC"
echo "=== 6. цена шлюза ПОСЛЕ ожидания (текущая, которую вор хотел бы получить) ==="
P_NOW=$(curl -s --max-time 20 "$G/price")
echo "$P_NOW"
echo
echo "=== 7. ЗАКРЫТИЕ — какую цену возьмёт? ==="
BEFORE=$(date -u +%s)
CLOSE=$(curl -s --max-time 45 -X POST "$G/close" -H 'Content-Type: application/json' -d "{\"id\":\"$ID\"}")
AFTER=$(date -u +%s)
echo "$CLOSE"
EXIT=$(echo "$CLOSE" | jqget "['exitPrice']")
echo
echo "================ ИТОГ ================"
echo "entryPrice (вход) : $ENTRY"
echo "exitPrice (шлюз вернул) : $EXIT"
echo "цена в момент клика : $P_NOW"
echo
if [ -z "$EXIT" ]; then
echo "ВЕРДИКТ: закрытие НЕ выполнилось (см. ответ выше)."
elif [ "$EXIT" = "$ENTRY" ]; then
echo "ВЕРДИКТ: exit == entry -> ставка осталась open (равные цены, отдельная задача)."
echo " Главное: цена НЕ взята произвольно с момента клика."
else
# Сравниваем exit с ценой, которая была бы при старом поведении
CUR=$(echo "$P_NOW" | jqget "['price']")
if [ -n "$CUR" ]; then
echo "Текущая цена в момент клика: $CUR (в целом виде $(python3 -c "print(int(float('$CUR')*10**8))" 2>/dev/null))"
fi
echo "Смотрим глазами: exitPrice должен соответствовать цене НА МОМЕНТ ЭКСПИРАЦИИ,"
echo "а не текущей. Если exitPrice == текущей цене клика — ОКНО ОТКРЫТО, фикс не работает."
fi
echo "закрытие заняло: $((AFTER-BEFORE))с"