Gas и Комиссии
Газ в TON — это валюта вычислений, и его понимание напрямую влияет на стоимость работы ваших контрактов и даже на их безопасность. В отличие от Ethereum, где пользователь платит за всё в одной транзакции, в TON газ распределяется по цепочке сообщений: каждое сообщение несёт газ для своей обработки. Неправильный расчёт газа — это не просто переплата, а потенциальная потеря средств или зависание контракта.
Модель комиссий в TON существенно отличается от Ethereum. Помимо gas за вычисления, в TON есть плата за хранение данных и пересылку сообщений между шардами.
Три типа комиссий
1. Gas (вычисления)
Каждая инструкция TVM потребляет gas. Gas оплачивается из TON, прикреплённых к сообщению.
- Простые операции (ADD, MUL): ~26 gas
- Работа с ячейками (NEWC, ENDC): ~500 gas
- Хеширование (HASHCU): ~100 gas
- Crypto операции: ~1000-15000 gas
Стоимость gas в TON фиксирована конфигурацией сети (не аукцион как в Ethereum):
1 gas = 1000 нано-TON (примерно)
Типичная транзакция: ~10 000 gas = 0.01 TON
2. Storage fees (хранение)
Уникальная для TON комиссия. Каждый контракт платит за хранение своего состояния в блокчейне:
- Оплата пропорциональна размеру данных (в битах и ячейках)
- Списывается автоматически при каждой транзакции
- Если баланс контракта < минимума → контракт замораживается
Storage fee = cells * cell_price + bits * bit_price
(за период с последней транзакции)
3. Forwarding fees (пересылка)
Плата за маршрутизацию сообщений между шардами:
- Пропорциональна размеру сообщения (в битах и ячейках)
- Если отправитель и получатель в одном шарде — forwarding fee минимален
- Межшардовая пересылка стоит дороже
Кто платит за gas?
В TON модель оплаты отличается от Ethereum:
| Тип сообщения | Кто платит | Как |
|---|---|---|
| External-in | Контракт-получатель | Из баланса контракта (после acceptMessage()) |
| Internal | Отправитель | Из TON, прикреплённых к сообщению |
| Bounce | Из остатка value | Автоматически вычитается из возвращаемых TON |
TON vs Ethereum: Модель оплаты gas
В Ethereum отправитель (EOA) оплачивает весь gas транзакции, включая вызовы вложенных контрактов. В TON каждое сообщение несёт свой “бюджет” на gas — TON, прикреплённые к сообщению. Контракт-получатель использует прикреплённые TON для оплаты своего gas и может прикрепить TON к исходящим сообщениям.
Gas и исполнение в EthereumGas modes при отправке сообщений
При создании исходящего сообщения контракт указывает mode, определяющий, сколько TON прикрепить:
| Mode | Описание |
|---|---|
| 0 | Отправить указанное количество TON |
| 64 | Перенести оставшийся gas входящего сообщения |
| 128 | Перенести весь баланс контракта |
| +1 | Оплатить forwarding fee отдельно |
| +2 | Игнорировать ошибки при отправке |
| +32 | Уничтожить контракт после отправки (если баланс = 0) |
Комбинация mode 64 — самая распространённая: контракт обрабатывает запрос и передаёт оставшийся gas дальше по цепочке.
Storage fees и заморозка контрактов
Критический момент: если баланс контракта становится отрицательным из-за storage fees, контракт замораживается (frozen). Замороженный контракт:
- Не обрабатывает входящие сообщения
- Все сообщения с bounce отскакивают обратно
- Может быть “разморожен” отправкой TON на его адрес
- После длительной заморозки может быть удалён из блокчейна
Это существенно отличается от Ethereum, где задеплоенный контракт существует бесконечно без дополнительных затрат.
Как защититься от заморозки?
- Поддерживать минимальный баланс — обычно 0.1-1 TON
- Оптимизировать storage — минимизировать количество ячеек и бит
- Использовать mode 64 — передавать gas по цепочке, а не накапливать
Расчёт стоимости транзакции
Полная стоимость транзакции в TON:
total_cost = gas_fees + storage_fees + fwd_fees_in + fwd_fees_out
Пример (swap на DEX):
gas_fees: 0.005 TON (обработка swap)
storage_fees: 0.001 TON (за хранение между транзакциями)
fwd_fees_in: 0.001 TON (входящее сообщение)
fwd_fees_out: 0.002 TON (2 исходящих сообщения)
─────────────────────
total: 0.009 TON
Фазы выполнения транзакции
Каждая транзакция в TON проходит через 5 последовательных фаз. Понимание этих фаз критически важно для правильного расчёта комиссий и обработки ошибок.
1. Storage Phase
Первая фаза начинается до обработки входящего сообщения:
- Вычисляется время с момента последней транзакции контракта
- Рассчитывается accumulated storage fee за этот период (пропорционально количеству ячеек и бит в состоянии)
- Storage fee вычитается из баланса контракта
- Если баланс становится отрицательным — контракт замораживается, транзакция прерывается
Storage fee может накопиться за месяцы неактивности контракта. Контракт с большим состоянием (тысячи ячеек), не получавший транзакций полгода, может потерять весь баланс на storage fees при первой входящей транзакции.
2. Credit Phase
- К балансу контракта добавляется value входящего сообщения (TON, прикреплённые отправителем)
- Эта фаза применяется только для internal сообщений
- Для external-in сообщений credit phase пропускается (value = 0)
Порядок “сначала storage, потом credit” означает, что storage fee списывается из старого баланса, а value сообщения добавляется после.
3. Compute Phase
Основная фаза — выполнение кода контракта в TVM:
- Загружается код контракта и его данные
- TVM выполняет инструкции, потребляя gas
- Контракт может создавать out_actions: отправка сообщений, обновление кода/данных, резервирование валюты
- Фаза завершается с exit_code: 0 или 1 — успех, другие значения — ошибка
- При ошибке compute phase out_actions отбрасываются
Gas за compute phase вычитается из баланса контракта (для external-in) или из прикреплённых TON (для internal).
4. Action Phase
Если compute phase завершилась успешно, обрабатывается список out_actions:
- Отправка сообщений — каждое исходящее сообщение ставится в очередь маршрутизации
- Обновление кода —
set_code()заменяет код контракта - Обновление данных — новое состояние записывается в storage
- Резервирование —
raw_reserve()фиксирует минимальный баланс
Действия обрабатываются последовательно. Если одно действие не может быть выполнено (например, недостаточно TON для отправки), оно пропускается или прерывает action phase (зависит от mode).
5. Bounce Phase
Последняя фаза активируется только при ошибке (в compute или action phase) для сообщений с флагом bounce: true:
- Генерируется bounce-сообщение обратно отправителю
- К bounce-сообщению прикрепляется оставшийся value (за вычетом gas)
- Тело bounce-сообщения содержит op-код 0xFFFFFFFF и первые 256 бит оригинального тела
- Контракт-отправитель может перехватить bounce и выполнить rollback-логику
Если сообщение было отправлено с bounce: false, bounce phase пропускается и оставшийся value остаётся на балансе контракта-получателя.
Порядок фаз: сводка
Частые ошибки
- Не резервируют достаточно газа для обработки bounced-сообщений, и если отправленное сообщение вернётся, у контракта может не хватить средств на обработку возврата.
- Жёстко кодируют значения газа (например, 0.05 TON) вместо использования динамического расчёта, хотя газовые цены могут измениться после обновления конфигурации сети.
- Забывают о storage fees: контракт с большим состоянием может «съесть» весь свой баланс на оплату хранения даже без активных транзакций.
- Не возвращают избыток газа (excess) отправителю после обработки сообщения, из-за чего газ накапливается на контракте вместо того, чтобы возвращаться пользователю.
Проверка знанийПочему в TON контракт может 'замёрзнуть', и как это предотвратить?
Проверьте понимание
Закончили урок?
Отметьте его как пройденный, чтобы отслеживать свой прогресс
Войдите чтобы оценить урок