6e7132e935
Механизм: шлюз берёт цену закрытия из локальной истории на момент 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). Остаток: в контракте верхней границы окна по-прежнему нет (второй слой, не критично); серверное авто-закрытие — следующая итерация.
81 lines
3.9 KiB
Bash
81 lines
3.9 KiB
Bash
#!/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))с"
|