Комиссии (Fee)
Что такое Fee
Fee (комиссия) — это процент от суммы трансфера, который удерживается бриджом при переводе токенов между сетями.
Зачем нужна fee?
Комиссия (fee) взимается бриджом при кросс-чейн трансферах токенов для покрытия операционных расходов и обеспечения экономической устойчивости протокола.
Важно
Комиссия взимается только на стороне EVM сети. На стороне TVM комиссия не применяется.
Кто получает fee?
- Комиссия накапливается на контракте MultiVault
- Получатель: адрес
governance(администратор контракта) - Вывод комиссий: функция
skim()переводит накопленные комиссии на адрес governance
Типы комиссий
Deposit Fee
Комиссия взимается при депозите токенов из EVM в TVM сеть.
Пользователь отправляет 1000 USDT → Fee 10 USDT (1%) → В TVM уходит 990 USDTКогда применяется:
- При вызове
deposit()на контракте MultiVault - При вызове
depositByNativeToken()для нативных токенов (ETH, BNB и т.д.)
Withdraw Fee
Комиссия взимается при выводе токенов из TVM в EVM сеть.
Пользователь выводит 1000 USDT из TVM → Fee 10 USDT (1%) → Получает 990 USDT в EVMКогда применяется:
- При вызове
saveWithdrawNative()/saveWithdrawAlien()на контракте MultiVault - После подтверждения события релеями
Схема взимания комиссии
┌─────────────────────────────────────────────────────────────────┐
│ EVM → TVM (Deposit) │
├─────────────────────────────────────────────────────────────────┤
│ User sends 1000 tokens │
│ ↓ │
│ MultiVault.deposit() │
│ ↓ │
│ Calculate fee: 1000 × depositFee / 10000 │
│ ↓ │
│ Fee (e.g. 10) stays on MultiVault │
│ ↓ │
│ 990 tokens transferred to TVM │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ TVM → EVM (Withdraw) │
├─────────────────────────────────────────────────────────────────┤
│ User initiates withdraw of 1000 tokens in TVM │
│ ↓ │
│ Event created, relays confirm │
│ ↓ │
│ User calls saveWithdraw*() on MultiVault │
│ ↓ │
│ Calculate fee: 1000 × withdrawFee / 10000 │
│ ↓ │
│ Fee (e.g. 10) stays on MultiVault │
│ ↓ │
│ User receives 990 tokens │
└─────────────────────────────────────────────────────────────────┘Default и Token-specific Fee
Два уровня настройки
Комиссии настраиваются на двух уровнях:
| Уровень | Описание | Когда используется |
|---|---|---|
| Default Fee | Глобальные значения по умолчанию | При активации нового токена |
| Token-specific Fee | Индивидуальные настройки для токена | После активации токена |
Default Fee
Глобальные настройки комиссий, разделённые по типу токена:
| Параметр | Описание |
|---|---|
defaultNativeDepositFee | Default deposit fee для Native токенов (изначально выпущены в TVM) |
defaultNativeWithdrawFee | Default withdraw fee для Native токенов |
defaultAlienDepositFee | Default deposit fee для Alien токенов (изначально выпущены в EVM) |
defaultAlienWithdrawFee | Default withdraw fee для Alien токенов |
Token-specific Fee
Индивидуальные настройки для каждого токена:
| Параметр | Описание |
|---|---|
tokens_[token].depositFee | Deposit fee для конкретного токена |
tokens_[token].withdrawFee | Withdraw fee для конкретного токена |
Как применяется fee
┌─────────────────────────────────────────────────────────────────┐
│ Схема применения fee при активации токена │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Первое использование токена │
│ ↓ │
│ Вызывается _activateToken() │
│ ↓ │
│ Определяется тип токена (Native или Alien относительно TVM) │
│ ↓ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Native токен │ │ Alien токен │ │
│ │ (из TVM) │ │ (из EVM) │ │
│ └────────┬────────┘ └────────┬────────┘ │
│ ↓ ↓ │
│ defaultNativeDepositFee defaultAlienDepositFee │
│ defaultNativeWithdrawFee defaultAlienWithdrawFee │
│ ↓ ↓ │
│ └───────────┬───────────┘ │
│ ↓ │
│ Копируются в tokens_[token].depositFee / withdrawFee │
│ ↓ │
│ Все последующие операции используют token-specific fee │
│ │
└─────────────────────────────────────────────────────────────────┘Важно
После активации токена изменение default fee НЕ влияет на этот токен. Для изменения fee уже активированного токена нужно явно вызвать setTokenDepositFee() / setTokenWithdrawFee().
Настройка комиссий
Установка default fee (для новых токенов):
setDefaultNativeDepositFee(100); // 1% для Native токенов (из TVM) deposit
setDefaultNativeWithdrawFee(50); // 0.5% для Native токенов withdraw
setDefaultAlienDepositFee(100); // 1% для Alien токенов (из EVM) deposit
setDefaultAlienWithdrawFee(50); // 0.5% для Alien токенов withdrawУстановка token-specific fee (для существующих токенов):
setTokenDepositFee(tokenAddress, 200); // 2% deposit для конкретного токена
setTokenWithdrawFee(tokenAddress, 100); // 1% withdraw для конкретного токенаСтруктура данных
Константы
| Константа | Значение | Описание |
|---|---|---|
MAX_BPS | 10,000 | 100% в basis points (1 BPS = 0.01%) |
FEE_LIMIT | 5,000 | Максимально допустимая fee = 50% |
Token структура
Хранит информацию о токене, включая комиссии. Каждый токен имеет индивидуальные настройки fee.
| Атрибут | Тип | Описание |
|---|---|---|
activation | uint | Номер блока активации токена |
blacklisted | bool | Флаг блокировки токена |
depositFee | uint | Комиссия при депозите (в BPS) |
withdrawFee | uint | Комиссия при выводе (в BPS) |
isNative | bool | true = Native токен (из TVM), false = Alien токен (из EVM) |
custom | address | Кастомный адрес токена |
Storage переменные
| Переменная | Тип | Описание |
|---|---|---|
tokens_ | mapping(address => Token) | Маппинг адрес токена → конфигурация |
defaultNativeDepositFee | uint | Default fee для депозита Native токенов (из TVM) |
defaultNativeWithdrawFee | uint | Default fee для вывода Native токенов |
defaultAlienDepositFee | uint | Default fee для депозита Alien токенов (из EVM) |
defaultAlienWithdrawFee | uint | Default fee для вывода Alien токенов |
Fee enum
| Значение | Описание |
|---|---|
Deposit | Комиссия при депозите |
Withdraw | Комиссия при выводе |
Расчёт комиссии
Формула
fee = amount × feeRate / MAX_BPSГде:
amount— сумма трансфераfeeRate— ставка комиссии в BPS (basis points)MAX_BPS= 10,000 (100%)
Функция расчёта
| Функция | Описание |
|---|---|
_calculateMovementFee() | Рассчитывает fee на основе типа операции (Deposit/Withdraw) и ставки токена |
Примеры расчёта
| Сумма | Fee Rate (BPS) | Fee Rate (%) | Комиссия |
|---|---|---|---|
| 1,000,000 | 10 | 0.1% | 1,000 |
| 1,000,000 | 100 | 1% | 10,000 |
| 1,000,000 | 500 | 5% | 50,000 |
| 1,000,000 | 5,000 | 50% | 500,000 (максимум) |
Управление комиссиями
Функции установки default fee
| Функция | Параметры | Описание |
|---|---|---|
setDefaultNativeDepositFee() | fee: uint | Устанавливает default deposit fee для Native токенов (из TVM) |
setDefaultNativeWithdrawFee() | fee: uint | Устанавливает default withdraw fee для Native токенов |
setDefaultAlienDepositFee() | fee: uint | Устанавливает default deposit fee для Alien токенов (из EVM) |
setDefaultAlienWithdrawFee() | fee: uint | Устанавливает default withdraw fee для Alien токенов |
Функции установки token fee
| Функция | Параметры | Описание |
|---|---|---|
setTokenDepositFee() | token: address, fee: uint | Устанавливает deposit fee для конкретного токена |
setTokenWithdrawFee() | token: address, fee: uint | Устанавливает withdraw fee для конкретного токена |
Вывод комиссий
| Функция | Параметры | Описание |
|---|---|---|
skim() | token: address | Переводит накопленные комиссии токена на адрес governance |
Функция рассчитывает накопленную fee как разницу между балансом контракта и заблокированной ликвидностью (liquidity[token]).
Права доступа
| Действие | Требуемая роль | Контракт |
|---|---|---|
| Установить default fee | governance | MultiVaultFacetFees |
| Установить token fee | governance | MultiVaultFacetFees |
| Вывести комиссии (skim) | governance | MultiVaultFacetFees |
Events
| Event | Параметры | Описание |
|---|---|---|
UpdateDefaultNativeDepositFee | fee | Изменение default deposit fee для Native токенов |
UpdateDefaultNativeWithdrawFee | fee | Изменение default withdraw fee для Native токенов |
UpdateDefaultAlienDepositFee | fee | Изменение default deposit fee для Alien токенов |
UpdateDefaultAlienWithdrawFee | fee | Изменение default withdraw fee для Alien токенов |
UpdateTokenDepositFee | token, fee | Изменение deposit fee для токена |
UpdateTokenWithdrawFee | token, fee | Изменение withdraw fee для токена |
SkimFee | token, skim_to_everscale, amount | Вывод накопленных комиссий |
Лимиты
| Параметр | Значение | Описание |
|---|---|---|
| MAX_BPS | 10,000 | 100% в basis points |
| FEE_LIMIT | 5,000 | Максимальная fee = 50% |
При попытке установить fee > FEE_LIMIT транзакция будет отклонена.
Fee в разных потоках
EVM → TVM (deposit)
- Пользователь вызывает
deposit()на MultiVault - Рассчитывается
depositFeeчерез_calculateMovementFee() - Fee вычитается из суммы трансфера
- Fee остаётся на контракте MultiVault (накапливается)
- В TVM сеть передаётся сумма за вычетом fee
TVM → EVM (withdraw)
- Пользователь инициирует withdraw в TVM сети (комиссия не взимается)
- Event контракт создаётся с информацией о трансфере
- Relay ноды подтверждают событие
- Пользователь вызывает
saveWithdraw*()на MultiVault в EVM - Рассчитывается
withdrawFeeчерез_calculateMovementFee() - Fee вычитается, пользователь получает сумму за вычетом fee
API Reference
POST /payload/build
Возвращает информацию о комиссии в ответе:
| Поле | Тип | Описание |
|---|---|---|
feeAmount | string | Рассчитанная комиссия в минимальных единицах токена |
tokenAmount | string | Сумма токенов после вычета комиссии |
Риски и Edge Cases
| Риск/Ошибка | Причина | Защита/Решение |
|---|---|---|
| Fee > Amount | Комиссия больше суммы трансфера | Транзакция revert (underflow) |
| Fee = 50%+ | Попытка установить fee выше лимита | Проверка fee <= FEE_LIMIT |
| Zero governance | Не задан получатель fee | governance устанавливается при инициализации |
| Token не активирован | Fee не задана для токена | Токен активируется автоматически при первом использовании |
| Изменение default fee | Не влияет на существующие токены | Нужно явно вызвать setTokenFee для каждого токена |
Коды ошибок
| Код ошибки | Описание |
|---|---|
"Fee: limit exceeded" | Попытка установить fee > FEE_LIMIT (5000 BPS = 50%) |
"Fees: no fees to skim" | Вызов skim() когда накопленная комиссия = 0 |
"Actors: only governance" | Вызов setDefaultFee не от адреса governance |
"Actors: only governance or management" | Вызов skim() не от governance/management |