Перейти к содержимому
Все статьи
Блокчейн

Газ в Ethereum: почему транзакции дорогие и как снизить расход

·30 октября 2026 г.· 11 мин чтения
Нужен смарт-контракт или dApp?Разработка смарт-контрактов

Транзакция в Ethereum дорогая по двум причинам: контракт тратит много газа на запись в постоянную память, и в момент отправки высока цена газа из-за спроса на место в блоке. Комиссия равна количеству газа, умноженному на сумму базовой цены и чаевых. Разработчик управляет первым множителем: запись в пустую ячейку storage стоит 20 000 газа, и именно её сокращают в первую очередь. Второй множитель снижают выбором времени и сети.

Как считается комиссия

С обновления London в 2021 году в Ethereum действует механизм EIP-1559. У каждого блока есть базовая цена газа (base fee), которая растёт, когда блоки переполнены, и падает, когда они полупустые. Базовая часть сжигается. Сверху пользователь добавляет чаевые валидатору (priority fee). Подробное объяснение есть на странице ethereum.org о газе.

СоставляющаяКто определяетЧто с ней можно сделать
Количество газа (gas used)Код контракта и данные вызоваОптимизировать контракт
Базовая цена (base fee)Загрузка сетиВыбрать время или другую сеть
Чаевые (priority fee)Пользователь или кошелёкНе переплачивать, если транзакция не срочная
Лимит газа (gas limit)Пользователь, обычно кошелёк оценивает самНеизрасходованный газ возвращается

Пример расчёта. Простой перевод эфира тратит ровно 21 000 газа. При базовой цене 1 gwei и чаевых 0,1 gwei комиссия составит 21 000 × 1,1 = 23 100 gwei, то есть 0,0000231 ETH. Вызов контракта, который меняет несколько ячеек storage, тратит в разы больше. Цифры цены газа здесь условные: актуальные значения показывают трекеры, например Etherscan Gas Tracker.

Какие операции съедают газ

ОперацияСтоимость в газеКомментарий
Базовая стоимость транзакции21 000Платится за любую транзакцию
Запись в пустую ячейку storage (0 → не 0)20 000 плюс 2 100 за холодный доступСамое дорогое в типичном контракте
Изменение уже занятой ячейки2 900 плюс холодный доступОбнуление частично возвращается
Чтение холодной ячейки storage2 100Первое обращение в транзакции (EIP-2929)
Повторное чтение той же ячейки100Тёплый доступ
Байт данных вызова: ненулевой / нулевой16 / 4Дорогие длинные аргументы
Transient storage (TSTORE/TLOAD)100Живёт только в рамках транзакции, EIP-1153

Цифры взяты из спецификаций EIP-2200, EIP-2929 и EIP-1153. Видно главное: любая работа с постоянной памятью на порядки дороже вычислений. Поэтому оптимизация газа — это прежде всего оптимизация storage.

9 приёмов оптимизации в Solidity

  1. Упаковывайте переменные. Ячейка storage — 32 байта. Переменные uint128, uint64, address и bool, объявленные подряд, компилятор кладёт в одну ячейку. Порядок объявления имеет значение.
  2. Читайте storage один раз. Сохраните значение в локальную переменную, работайте с ней и запишите результат одной операцией.
  3. **Используйте constant и immutable.** Параметры, которые не меняются после деплоя, не должны занимать storage.
  4. Собственные ошибки вместо строк. error InsufficientBalance(); дешевле в деплое и при откате, чем длинная строка в require.
  5. **calldata вместо memory для внешних аргументов.** Массивы и строки только для чтения не нужно копировать в память.
  6. Не храните то, что можно вычислить или прочитать из событий. История операций для интерфейса живёт в логах, а не в массивах storage.
  7. Избегайте неограниченных циклов. Цикл по растущему массиву однажды перестанет помещаться в лимит блока. Используйте схему, где пользователь сам забирает своё (pull вместо push).
  8. Transient storage для временных флагов. Блокировка от повторного входа в ReentrancyGuardTransient из OpenZeppelin стоит дешевле классической.
  9. Включите оптимизатор и измеряйте. forge snapshot и forge test --gas-report в Foundry показывают расход по функциям до и после изменений.

Пример упаковки переменных

Учебный пример. Три переменные, объявленные в порядке uint256 amount; address owner; bool active;, займут две ячейки: amount — целую, а owner (20 байт) и active (1 байт) поместятся во вторую. Если вместо uint256 хватит uint96, то amount и owner вместе займут 32 байта, а active уйдёт в следующую ячейку. Выигрыш появляется, только когда переменные читаются и пишутся вместе. Иначе упаковка может даже добавить расход на маскирование битов.

Газ на уровне архитектуры

Самая большая экономия обычно достигается не в коде, а в решениях. Нужно ли хранить данные в блокчейне или достаточно их хеша? Можно ли объединить несколько операций пользователя в одну транзакцию? Можно ли подписывать намерения вне сети и исполнять пачкой? Подписи EIP-712 и permit убирают отдельную транзакцию approve, но требуют аккуратной защиты, о ней — в статье о повторе подписи.

РешениеЭкономияЦена решения
Хранить хеш вместо данныхБольшаяДанные нужно хранить и отдавать отдельно
Merkle-дерево для списка адресов (вайтлист, раздача)Большая при длинных спискахСложнее генерация доказательств на бэкенде
Перенос в L2Комиссия для пользователя ниже в разыДругая модель безопасности и вывода средств
Пакетная обработкаСредняяРиск упереться в лимит газа блока
Подписи вне сети (permit)Минус одна транзакцияЗащита от повтора подписи

После обновления Dencun в марте 2024 года (EIP-4844) публикация данных роллапов в Ethereum подешевела, и комиссии в L2 заметно упали. Если пользователи платят много за каждое действие, честно рассмотрите другую сеть. Сравнение — в статье о выборе сети.

Из чего состоит комиссия в L2

В роллапах вроде Arbitrum и Base комиссия состоит из двух частей. Первая — плата за исполнение в самой сети L2, она считается так же, как в Ethereum, но цена газа там обычно ниже. Вторая — доля расходов на публикацию данных транзакции в Ethereum. Поэтому в L2 особенно важно экономить не только storage, но и размер данных вызова: длинные массивы аргументов и лишние байты обходятся дороже, чем кажется по одной лишь цене исполнения.

Практический вывод для разработчика: измеряйте расход газа в той сети, куда реально деплоите, а не только в локальной. Для этого Foundry умеет запускать тесты на форке нужной сети с --fork-url, а трекеры и обозреватели каждой сети показывают актуальные цены.

Почему транзакция падает с ошибкой «out of gas»

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

Оптимизацию газа мы делаем вместе с тестами и ревью, а не отдельно от них. Если ваш контракт стал слишком дорогим для пользователей, опишите задачу на странице разработки смарт-контрактов. Перед изменениями в работающем контракте стоит пройти аудит смарт-контракта.

Вопросы и ответы

Почему газ в Ethereum то дорогой, то дешёвый?

Базовая цена газа автоматически растёт, когда блоки переполнены, и падает, когда спрос низкий. Поэтому одна и та же операция стоит по-разному в разное время суток и в дни ажиотажа.

Сколько газа тратит перевод ERC-20?

Обычно несколько десятков тысяч газа: базовые 21 000 плюс чтение и запись балансов. Точная цифра зависит от реализации токена и от того, был ли у получателя ненулевой баланс.

Возвращается ли неизрасходованный газ?

Да. Пользователь платит только за фактически потраченный газ, а лимит — это верхняя граница. Если транзакция откатилась, газ, потраченный до отката, не возвращается.

Что такое gwei?

Это единица цены газа: одна миллиардная доля эфира. Когда кошелёк показывает цену газа 1 gwei, это значит, что каждая единица газа стоит 0,000000001 ETH.

Стоит ли переходить на L2 ради экономии газа?

Если пользователи совершают много мелких операций, обычно да. Но у L2 другая модель безопасности, вывод средств в Ethereum может занимать время, а ликвидность и аудитория отличаются.

Нужна помощь с проектом?

Обсудим задачу и предложим решение — от сайта до SaaS и защиты.

Связаться