Skip to content

Лимиты (Limits) ​

Что такое лимиты ​

Система лимитов в MultiVault защищает от мгновенного опустошения контракта при компрометации relay-нод или эксплойте уязвимости. Лимиты применяются к двум типам операций:

  1. Лимиты на депозит — ограничивают максимальное количество токенов, которое может храниться на MultiVault
  2. Лимиты на вывод — ограничивают сумму вывода за одну транзакцию и суммарно за 24 часа

Важно

Лимиты существуют только на стороне EVM сети.

Зачем нужны лимиты? ​

  • Компрометация relay-нод — лимиты замедлят вывод средств и дадут время на обнаружение атаки
  • Эксплойты смарт-контрактов — лимиты блокируют крупные транзакции
  • Защита ликвидности — предотвращают моментальное опустошение пулов
  • Fraud detection window — превышение лимитов создаёт pending withdrawal, требующий одобрения

Race condition при approve

Governance может одобрить pending, но баланс MultiVault окажется недостаточен — статус изменится на Approved, но токены не будут переведены. Для завершения потребуется forceWithdraw() или Fill через LP (см. Liquidity Request).

Лимиты на депозит (Deposit Limits) ​

Ограничивают максимальный баланс токена на MultiVault.

ПараметрОписание
depositLimitМаксимальный баланс токена на MultiVault
ПрименяетсяТолько для Alien токенов
При превышенииДепозит отклоняется (revert)

Депозит отклоняется, если сумма текущего баланса MultiVault и суммы депозита превысит установленный лимит. Если лимит не установлен (равен нулю), проверка пропускается.

Почему только для Alien

Native токены при депозите (трансфере EVM→TVM) сжигаются (burn), а не хранятся на MultiVault. Поэтому баланс MultiVault для native токенов всегда ~0.

Лимиты на вывод (Withdrawal Limits) ​

Ограничивают суммы вывода токенов из MultiVault.

ПараметрОписание
undeclaredЛимит на одну транзакцию (per-transaction limit)
dailyЛимит на сумму за 24 часа (per-period limit)
enabledФлаг включения лимитов для токена
ПрименяетсяДля Alien и Native токенов
При превышенииСоздаётся Pending Withdrawal

Инвариант: daily >= undeclared

Вывод проходит мгновенно, если выполняются оба условия одновременно. Если лимиты отключены для токена, проверка пропускается.

Условие 1: Per-transaction (undeclared) ​

Сумма текущей транзакции должна быть строго меньше лимита на одну транзакцию (undeclared).

Важно: Транзакция ровно на сумму лимита требует одобрения.

Условие 2: Per-period (daily) ​

Сумма текущей транзакции плюс уже выведенное за период минус одобренное governance должна быть строго меньше суточного лимита (daily).

  • Уже выведено (total) — суммарный вывод за текущий 24-часовой период
  • Одобрено (considered) — суммы, одобренные governance (вычитаются, чтобы не блокировать последующие легитимные выводы)

Пример расчёта ​

ПараметрЗначение
Undeclared limit10,000 USDT
Daily limit50,000 USDT
Уже выведено за период (total)30,000 USDT
Одобрено governance (considered)20,000 USDT
Запрос на вывод15,000 USDT

Проверка 1 (per-transaction):

15,000 < 10,000 → ❌ FAIL

Проверка 2 (per-period):

15,000 + 30,000 - 20,000 = 25,000 < 50,000 → ✅ PASS

Результат: Хотя проверка 2 прошла, проверка 1 провалилась → создаётся Pending Withdrawal со статусом Required.

Механизм 24-часовых периодов ​

Вычисление ID периода ​

ID периода вычисляется делением timestamp на длительность периода (86400 секунд = 24 часа). Все транзакции в рамках одних суток получают одинаковый ID периода.

Примеры ​

TimestampДата/время (UTC)Period ID
17040672002024-01-01 00:00:0019723
17041535992024-01-01 23:59:5919723
17041536002024-01-02 00:00:0019724

Автоматический сброс ​

При переходе в новый период счётчики (total, considered) автоматически обнуляются (новая запись в маппинге).

Важно: Используется eventTimestamp из TVM события, а не block.timestamp. Это предотвращает манипуляции через задержку исполнения транзакции.

Поведение при превышении лимитов ​

Когда вывод не проходит проверку лимитов, создаётся Pending Withdrawal со статусом Required — тот же объект, что и при нехватке ликвидности (см. Liquidity Request), но с другим статусом и набором действий.

Доступные действия ​

Pending Withdrawal со статусом Required ждёт решения governance:

ДействиеКто можетОписание
Approvegovernance / withdrawGuardianОдобрить вывод — если ликвидность есть, токены отправляются сразу
Rejectgovernance / withdrawGuardianОтклонить вывод — получатель может вернуть токены через Cancel
Force WithdrawЛюбойПосле Approve — протолкнуть вывод, если автоматически не прошёл

TIP

Действия Fill, Bounty, Cancel доступны для статуса NotRequired — см. Liquidity Request.

Как это работает в контракте

Оба метода (saveWithdrawNative, saveWithdrawAlien) сначала создают Pending со статусом NotRequired. Затем, если лимиты не пройдены, статус сразу обновляется на Required. Для Native токенов единственная причина Pending — лимиты, поэтому статус всегда Required. Для Alien — зависит от того, что именно не прошло: баланс, лимиты или оба.

Диаграмма создания Pending ​



Детали: Approve или Reject ​

Кто может вызвать: Только governance или withdrawGuardian

Требования:

  • Текущий статус должен быть Required
  • Можно установить только Approved или Rejected

Логика при Approve:

  • Если баланс MultiVault достаточен ИЛИ это Native токен → автоматический вывод
  • Иначе просто меняется статус на Approved

Callback: ❌ НЕ вызывается

Функция setPendingWithdrawalApprove проверяет, что текущий статус Required и что устанавливается Approved или Rejected. При установке Approved, если баланс MultiVault достаточен или это Native токен, автоматически выполняется вывод. В любом случае сумма добавляется к considered для текущего периода.


Детали: Force Withdraw (после Approve) ​

Кто может вызвать: Любой адрес

Требования:

  • Статус Approved (или NotRequired)
  • amount > 0

Логика:

  • amount переводится получателю в полном объёме
  • Bounty никому не зачисляется (идёт получателю)

Callback: ✅ Вызывается

Функция forceWithdraw принимает массив pending withdrawals и для каждого: обнуляет сумму pending, переводит получателю полную сумму (без вычета bounty) и вызывает callback.

Структура данных ​

Storage маппинги ​

МаппингКлючОписание
tokens_token addressИнформация о токене, включая depositLimit
withdrawalLimits_token addressundeclared, daily, enabled
withdrawalPeriods_token → period IDtotal (суммарный вывод), considered (одобренное governance)
pendingWithdrawals_recipient → IDПараметры отложенного вывода
pendingWithdrawalsPerUserrecipientСчётчик pending (используется как ID)
pendingWithdrawalsTotaltoken addressСуммарный pending по токену

ApproveStatus ​

ЗначениеСтатусОписание
0NotRequiredОдобрение не требуется (недостаток средств в MultiVault)
1RequiredТребуется одобрение (превышение лимитов)
2ApprovedОдобрено governance или withdrawGuardian
3RejectedОтклонено

Управление лимитами ​

Установка лимитов ​

Все функции требуют модификатор onlyGovernance.

Deposit Limit ​

Функция setDepositLimit устанавливает максимальный баланс токена на MultiVault.

Withdrawal Limits ​

Доступны следующие функции управления:

  • setDailyWithdrawalLimits — устанавливает суточный лимит (проверяет, что он не меньше undeclared)
  • setUndeclaredWithdrawalLimits — устанавливает лимит на транзакцию (проверяет, что он не больше daily)
  • enableWithdrawalLimits — включает лимиты для токена
  • disableWithdrawalLimits — отключает лимиты для токена

События ​

СобытиеПараметрыКогда эмитится
UpdateDailyWithdrawalLimitstoken, limitИзменён daily limit
UpdateUndeclaredWithdrawalLimitstoken, limitИзменён undeclared limit
UpdateWithdrawalLimitStatustoken, statusВключены/отключены лимиты
PendingWithdrawalCreatedrecipient, id, token, amount, payloadIdСоздан pending при превышении лимитов
PendingWithdrawalUpdateApproveStatusrecipient, id, approveStatusApprove или Reject
PendingWithdrawalWithdrawrecipient, id, amountАвтовывод при approve

TIP

События Fill, Cancel, Bounty описаны в разделе Liquidity Request.

Права доступа ​

ДействиеТребуемая роль
Установить deposit limitgovernance
Установить withdrawal limitsgovernance
Включить/отключить лимитыgovernance
Approve/Reject pendinggovernance ИЛИ withdrawGuardian

Коды ошибок ​

ОшибкаПричина
"Deposit: limits violated"Депозит превышает depositLimit для токена
"Settings: daily limit < undeclared"Попытка установить daily < undeclared или undeclared > daily
"Pending: wrong current approve status"Попытка Approve/Reject для pending, который не в статусе Required
"Pending: wrong approve status"Указан недопустимый новый статус (не Approved и не Rejected)
"Pending: zero amount"Pending уже исполнен (amount = 0)
"Pending: params mismatch"Массовый Approve: длины массивов ID и статусов не совпадают

ChainConnect Bridge Documentation