Безопасность Web3: с нуляЧасть 11 из 12SmartAlert6 мин чтения

Фиксированный порог или норма по часам: почему одно число всегда врёт

Фиксированный порог шумит днём и слепнет ночью. Как работает сравнение часа с тем же часом прошлых дней и когда фиксированное число всё же верно.

Первый алерт на активность, который пишет большинство команд: «сообщи, если транзакций за час больше N». Или наоборот, «меньше N», то есть контракт затих. Это просто, и для большинства контрактов это неверно. Эта часть объясняет почему, чем заменить и где фиксированное число всё же правильный инструмент.

Она продолжает часть 10: там мы следили за значением, которое никогда не должно быть определённым числом. Здесь следим за значением, которое меняется всегда, и вопрос в том, что считать «необычным».

У контракта есть день и ночь

Ончейн-активность идёт за людьми. Кредитный пул, пара на DEX или игровой контракт загружены, когда пользователи не спят, и тихи, когда спят. Один и тот же час повторяется изо дня в день. В недельных данных большого кредитного пула в BNB Chain около 120 транзакций в час были нормой в 20:00 UTC, а около 500 — нормой в полдень1.

Теперь выберите одно число.

  • Поставить под день. «Больше 500 в час» днём почти молчит. В 20:00 час должен вырасти вчетверо, чтобы сработало, и необычный вечер проходит незамеченным.
  • Поставить под ночь. «Больше 170 в час» ловит скачок в 20:00 и срабатывает почти каждый час суток, потому что днём норма выше. Это уже не алерт, а журнал.
  • Вариант «затих» («меньше 150») каждую ночь срабатывает на обычной тишине, а когда в полдень контракт падает с 500 до 200, не видит ничего.

Числа, которое верно и для полудня, и для 20:00, нет. Любой выбор меняет ночную слепоту на дневной шум.

Вторая половина проблемы тяжелее. Порог ставят один раз. Через квартал у контракта больше пользователей, норма сместилась, алерт срабатывает весь день. Команда его глушит, и с этого момента мониторинга нет. Так чаще всего и умирают алерты, и никакая настройка в первый день этого не предотвращает.

Идея: сравнивать час с тем же часом

Перестаньте сравнивать с константой. Сравнивайте каждый час с тем, каким этот час бывает обычно.

Для сегодняшних 20:00 берём значение в 20:00 за каждый из предыдущих семи дней. Их описывают два числа:

  • обычное значение — их медиана;
  • обычный разброс — медиана того, насколько каждое значение отстоит от медианы (MAD), умноженная на 1,4826, чтобы масштаб совпал со стандартным отклонением.

Правило срабатывает, когда сегодняшнее значение дальше от медианы больше чем на *k* разбросов. Граница получается медиана + k × 1,4826 × MAD. В полдень медиана высокая и полоса широкая. В 20:00 низкая и узкая. Порог идёт за часами и за контрактом: когда пул вырос, медианы следующей недели растут вместе с ним.

В SmartAlert это условие называется «отклонение от нормы». Это описанная формула, а не обученная модель: её можно пересчитать вручную по тем же данным. Мы считаем, что алерту, который можно проверить, доверяют, а алерт, которому не доверяют, глушат.

Почему медиана, а не среднее

Семидневное окно часто содержит то самое, что вы хотите поймать: прошлую аварию, эирдроп, взбесившегося бота. Среднее и стандартное отклонение этот день впитывают. Полоса расширяется, и следующий такой же инцидент выглядит нормой. Правило, выучившее инцидент, перестаёт видеть инциденты.

Медиана и MAD одного плохого дня из семи почти не замечают. Один выброс сильно двигает среднее и почти не двигает медиану, поэтому даже испорченная история даёт пригодную норму.

Нижняя граница разброса

На очень ровном ряду MAD бывает нулевым. Тогда любое отличие от медианы выглядит бесконечно необычным, и тихий контракт срабатывал бы на каждой транзакции. Поэтому у разброса есть нижняя граница в абсолютных единицах: большее из 1 и 10% медианы. В вечерний час из примера выше ширину полосы задаёт именно эта граница, а не данные.

Единственная ручка: чувствительность

*k* — это чувствительность, по умолчанию 3, в SmartAlert от 1 до 10. Меньше *k* — уже полоса и больше алертов. Больше *k* — меньше алертов, и нужен более крупный скачок.

Угадывать её не нужно. Помогают две вещи.

  • Бэктест. До запуска правила посмотрите на метрику, полосу и точки, в которых правило сработало бы за прошлые дни. Двигайте *k*, пока отметки не станут теми, о которых вы хотели бы знать.
  • От своей терпимости. Скажите «просыпаться готов не чаще двух раз в неделю», и инструмент подберёт *k*, при котором на выбранной истории будет не больше такого числа алертов. Свою терпимость к шуму человек называет легко. Сколько транзакций в час «нормально», он обычно не знает.

Ещё два параметра важны на практике.

  • Направление. Для числа свопов скачок часто безразличен, а падение до нуля — инцидент. Выберите только «ниже», только «выше» или оба.
  • Свой порог для часа. Если вы знаете, что в 03:00 UTC работает пакет кипера, можно задать для этого часа свой порог, и он заменит норму в этом часе.

Тот же час прошлых дней или тот же день недели

У недели тоже есть форма. DEX может быть тихим в воскресенье и оживлённым во вторник. Базу сравнения можно выбрать:

тот же час, прошлые 7 дней
С чем сравниваеттот же час за каждый из последних 7 дней
Точек7
тот же час, прошлые 28 дней
С чем сравниваеттот же час за последние 28 дней
Точек28
тот же день недели и час, прошлые 4 недели
С чем сравниваетнапример, воскресенье 20:00 за последние 4 воскресенья
Точек4

По умолчанию — семь дней. Она быстро подстраивается, но выходные сравниваются с буднями. База по дню недели это исправляет, но точек для сравнения всего четыре. Четыре меньше стандартного минимума в пять, поэтому выбирайте её вместе с меньшим минимумом.

Когда фиксированный порог — правильный инструмент

Норма не заменяет фиксированные числа. Она заменяет их там, где граница берётся из статистики. Фиксированное число верно, когда граница приходит извне:

  • коэффициент обеспечения ниже 150%;
  • баланс ниже суммы завтрашних выплат;
  • комиссия выше записанной в договоре.

Здесь значение может месяцами стоять у опасной границы. Если взять «необычно для этого часа», опасная граница станет нормой, и правило замолчит ровно там, где должно кричать. Итак: граница из договора, кода или регламента — фиксированный порог. Граница «не как обычно» — норма.

Где норма пока не работает

  • Нет истории — нет нормы. Норме нужны данные из прошлого: для базы за 7 дней — семь дней ряда. Пока их нет, правило сохранено, но не вычисляется, а интерфейс показывает дату, с которой норма появится. На этот период можно задать запасной порог.
  • Запуск и быстрый рост. Если контракт запускается или идёт эирдроп, норма отстаёт, и правило говорит «выше нормы» час за часом. Поставьте правилу «Тишина до…» на 1, 3, 7 дней или до даты: оно продолжит считать, запишет срабатывания как «не отправлено: тишина» и включится само.
  • Атаки, которые выглядят нормально. Эксплойт, двигающий $10M несколькими транзакциями, не меняет число транзакций загруженного контракта. Нормы активности ловят изменение частоты, а не одну транзакцию. Для этого нужен порог в долларах на выводе, а он по природе фиксированный.

Как поймать

  1. Для частоты берите норму. Рецепты transfer-spike, swap-spike и contract-went-quiet — это норма со средней чувствительностью: первые два срабатывают выше неё, последний ниже. В своём правиле выбирайте «ниже» для контракта, который не должен останавливаться, и «выше» для того, который не должны долбить.
  2. Бэктест до включения. Откройте правило на 30 днях истории, затем двигайте *k* или задайте число алертов в неделю, которое готовы терпеть.
  3. Для денежных границ берите фиксированные числа в долларах. large-transfer-usd, treasury-below-usd. Фиксированный и баланс кошелька, который платит: keeper-gas-runway уже переводит траты в дни запаса.
  4. Пересмотрите через неделю. Если правило срабатывает на каждом обычном часе, поднимите *k*. Если не срабатывает никогда, проверьте на бэктесте, что оно вообще могло.

Источники

  1. 1.SmartAlert, Aave V3 Pool в BNB Chain, транзакции в час, неделя октября 2026. Числа в тексте — типичный уровень каждого часа, округлённый. ↩

Попробуйте бесплатно

Достаточно адреса. Первые 14 дней действуют лимиты Pro, а правила проверяются на истории до включения.

Ещё статьи