Лимиты (Limits)
Что такое лимиты
Лимиты — это механизм защиты бриджа от масштабных атак и эксплойтов. Они ограничивают суточный объём переводов для каждого токена отдельно.
Назначение:
- Защита от drainage атак (массовый вывод средств при взломе)
- Ограничение потенциального ущерба при эксплойте
- Время для реагирования на аномальную активность
Где применяется:
- Контракты
ProxyMultiVaultAlienJetton_V3(alien токены) - Контракты
ProxyMultiVaultNativeJetton_V3(native токены)
Типы лимитов
Система поддерживает два типа суточных лимитов для каждого токена:
| Тип | Описание | Применение |
|---|---|---|
| Incoming (входящий) | Ограничение на объём токенов, поступающих в сеть | Депозиты из других сетей в TVM |
| Outgoing (исходящий) | Ограничение на объём токенов, выводимых из сети | Вывод из TVM в другие сети |
Особенности
- Лимиты устанавливаются на конкретный токен, а не глобально
- Каждый лимит опционален — может быть не установлен (
null) - Если лимит не установлен — проверка пропускается, трансфер проходит без ограничений
- Лимиты не зависят от адреса пользователя — это общий суточный объём для токена
Структура данных
DailyLimits
struct DailyLimits {
optional(uint128) incomingLimit; // Лимит на входящие (null = без лимита)
uint128 dailyIncomingVolume; // Текущий суточный объём входящих
optional(uint128) outgoingLimit; // Лимит на исходящие (null = без лимита)
uint128 dailyOutgoingVolume; // Текущий суточный объём исходящих
uint32 dayStartTimestamp; // Timestamp начала текущего "дня"
}Механизм проверки лимитов
Алгоритм проверки

Определение "дня"
День определяется делением block.timestamp на 86400 (секунд в сутках).
- День сбрасывается в 00:00 UTC
- При смене дня объёмы обнуляются
- Обновляется
dayStartTimestamp
Когда проверяется лимит
| Направление | Момент проверки |
|---|---|
| Incoming (deposit) | После подтверждения event relays |
| Outgoing (withdraw) | При получении токенов на burn/transfer |
Формула проверки
- Incoming:
dailyIncomingVolume + amount > incomingLimit→ LimitReached - Outgoing:
dailyOutgoingVolume + amount > outgoingLimit→ LimitReached
Важно
Проверка > (строго больше), не >=. Если лимит = 100 и текущий volume = 0, то трансфер на 100 пройдёт (100 > 100 = false).
Сценарии при достижении лимита
Outgoing (исходящий) — LimitReached
При превышении лимита на вывод:
- Токены возвращаются отправителю
- Событие
OutgoingLimitReached(token)эмитится - Трансфер не создаётся
Incoming (входящий) — LimitReached
При превышении лимита на ввод:
- Event контракт переходит в статус
LimitReached(код 5) - Устанавливается
limitApproverадрес - Событие
LimitReached(approver)эмитится - Трансфер откладывается до решения approver'а
Действия при LimitReached (входящий)
LimitApprover может выполнить одно из трёх действий:
| Действие | Функция | Результат |
|---|---|---|
| Approve | approveLimit() | Трансфер выполняется, токены минтятся получателю |
| Cancel | cancel() | Токены возвращаются в исходную сеть |
| Reject | rejectLimit() | Event отклоняется, средства остаются в исходной сети |
Retry механизм
Пользователь или инициализатор могут вызвать retry() для повторной попытки трансфера (например, после сброса лимита в новые сутки).
Восстановление лимита
Лимит автоматически сбрасывается в 00:00 UTC следующего дня. Ручной сброс не предусмотрен — только изменение самого лимита через setTokenDailyLimits().
Управление лимитами
Установка лимитов
setTokenDailyLimits(_token, _incomingLimit, _outgoingLimit)Параметры:
_token— адрес токена_incomingLimit— лимит на входящие (null = без лимита)_outgoingLimit— лимит на исходящие (null = без лимита)
Права доступа: Только owner контракта
Установка LimitApprover
setLimitApprover(approverAddress)Права доступа: Только owner контракта
Чтение лимитов
getDailyLimits(token)— возвращает структуру DailyLimits для токенаgetLimitApprover()— возвращает адрес текущего approver'а
Лимиты по умолчанию
По умолчанию лимиты не установлены (null). Это означает неограниченные трансферы до явной установки лимитов администратором.
API/Contract Reference
Proxy контракты (Alien и Native)
| Функция | Доступ | Описание |
|---|---|---|
setTokenDailyLimits() | owner | Установить/изменить лимиты для токена |
getDailyLimits() | public | Получить текущие лимиты и объёмы |
setLimitApprover() | owner | Установить адрес approver'а |
getLimitApprover() | public | Получить адрес approver'а |
Event контракты
| Функция | Доступ | Описание |
|---|---|---|
approveLimit() | limitApprover | Одобрить трансфер при LimitReached |
cancel() | limitApprover | Отменить и вернуть средства |
rejectLimit() | limitApprover | Отклонить трансфер |
retry() | recipient/initializer | Повторить попытку трансфера |
События (Events)
| Событие | Когда эмитится |
|---|---|
OutgoingLimitReached(address token) | При превышении исходящего лимита |
LimitReached(address approver) | При превышении входящего лимита |
Ошибки и Edge Cases
Коды ошибок
| Код | Константа | Описание |
|---|---|---|
| 2335 | SENDER_IS_NOT_LIMIT_APPROVER | Вызывающий не является limit approver |
| 2324 | WRONG_STATUS | Неверный статус для операции |
Edge Cases
| Ситуация | Поведение |
|---|---|
| Лимит = 0 | Любой трансфер > 0 превысит лимит |
| Лимит = null | Без ограничений |
| Первый трансфер дня | Объём сбрасывается, затем добавляется сумма |
| Трансфер точно равен лимиту | Пройдёт (проверка >, не >=) |
| limitApprover = zero address | approveLimit() завершится с ошибкой |
Важные замечания
- Частичное выполнение НЕ поддерживается — трансфер либо проходит полностью, либо отклоняется
- Лимиты проверяются ПОСЛЕ подтверждения relays для incoming трансферов
- Лимиты проверяются ДО создания event для outgoing трансферов
- При outgoing LimitReached токены возвращаются мгновенно, не требуют ручного вмешательства