Оптимізація газу смарт-контрактів

Проєктуємо та розробляємо блокчейн-рішення повного циклу: від архітектури смарт-контрактів до запуску DeFi-протоколів, NFT-маркетплейсів та криптобірж. Аудит безпеки, токеноміка, інтеграція з наявною інфраструктурою.
Показано 1 з 1Усі 1306 послуг
Оптимізація газу смарт-контрактів
Середній
~2-3 дні
Часті запитання

Напрямки блокчейн-розробки

Етапи блокчейн-розробки

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1308
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1221
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    921
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1149
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    612
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    886

Оптимізація газу смарт-контрактів

Деплой контракту обійшовся в 0.8 ETH замість очікуваних 0.3. Або користувачі платять по $15 за кожен transfer() при gas price 30 gwei, тоді як конкуренти — по $4. Це не питання «коли спаде навантаження мережі». Це питання storage layout, неоптимальних opcodes та паттернів, які компілятор Solidity не виправляє за вас.

Звідки береться лишний газ

Storage — головний джерело втрат

SSTORE коштує 20 000 gas при записі в холодний слот, 2 900 gas при оновленні теплого. SLOAD — 2 100 gas для холодного, 100 для теплого (EIP-2929). Саме тому архітектура сховища визначає 60-80% вартості контракту.

Slot packing — перший інструмент. EVM зберігає дані в 32-байтових слотах. Якщо оголосити змінні так:

uint128 a; // слот 0
uint256 b; // слот 1 — ОКРЕМИЙ слот, хоча міг би упакуватися
uint128 c; // слот 2

Отримуємо три слоти. Переупорядкування:

uint128 a; // слот 0, байти 0-15
uint128 c; // слот 0, байти 16-31 — упаковані!
uint256 b; // слот 1

Дає два слоти. На контракті з 10 000 деплойм економія — сотні ETH сумарно по екосистемі.

На практиці: один крупний DeFi-проект прийшов до нас з ERC-1155 контрактом, де структура TokenInfo займала 3 слоти замість 1. Переупорядкування полів та заміна uint256 decimals на uint8 decimals зрізали 62% газу на mint().

Mappings vs Arrays

mapping(uint256 => address) — O(1) доступ, gas-ефективен. address[] з пошуком за значенням — O(n) та в 99% випадків помилка архітектури. Якщо потрібна ітерація — індексуй через события, читай off-chain через The Graph.

Неочевидне джерело: keccak256 на коротких рядках

string memory name в функції, яка викликається тисячі разів — це ABI encoding overhead. Заміна рядків на bytes32 константи там, де рядки відомі заранее, дає 200-500 gas на виклик.

Інструменти аналізу

Інструмент Що показує
Hardhat Gas Reporter Gas на кожний виклик функції в тестах
Foundry forge test --gas-report Те ж, але швидше та з diff між комітами
eth-gas-reporter Деталізація по opcodes через --verbose
Tenderly Gas Profiler Breakdown по EVM-трейсу реальної транзакції
Remix Gas Estimation Швидка перевірка без setup

Foundry — переважний вибір. forge snapshot створює .gas-snapshot файл, який можна коммітити в репозиторій та відслідковувати регресії газу в CI:

forge snapshot
# змінюємо код
forge snapshot --diff

Різниця одразу видна по рядках для кожної функції.

Конкретні паттерни оптимізації

Custom errors замість require з рядками

// До: 24 000 gas на деплой однієї рядка
require(amount > 0, "Amount must be positive");

// Після: економія ~200 gas per revert + менше байткоду
error AmountZero();
if (amount == 0) revert AmountZero();

Custom errors (EIP-838) стали стандартом з Solidity 0.8.4. Рядки в require — це bytecode, який збільшує вартість деплою та revert.

Unchecked arithmetic

З Solidity 0.8.0 усі арифметичні операції перевіряють overflow за замовчуванням. Перевірка коштує ~100 gas per operation. Там, де overflow математично неможливий:

unchecked {
    ++i; // у циклі for — стандартний паттерн
    total += amounts[i]; // якщо суми обмежені та перевірені вище
}

На циклі з 100 ітерацій — економія 10 000+ gas.

Immutable та constant

constant — значення вбудовується в байткод, SLOAD не потрібен. immutable — значення записується в байткод при деплої, читається як PUSH32. Обидва в ~3 рази дешевше читання зі storage. Адреса токена, fee basis points, адреса owner у контракті, який не апгрейдиться — усе це кандидати на immutable.

Calldata vs memory для вхідних параметрів

// memory — копіює дані в пам'ять
function process(uint256[] memory ids) external

// calldata — читає прямо з calldata, не копіює
function process(uint256[] calldata ids) external

Для зовнішніх функцій (external), де дані тільки читаються — calldata дешевше. Різниця зростає з розміром масиву: на масиві з 50 елементів — 3 000-5 000 gas.

Процес оптимізації

Аудит baseline. Запускаємо всі тести з forge test --gas-report, фіксуємо baseline. Ніяких змін без вимірювань до та після.

Профілювання через Tenderly. Беремо реальні транзакції з mainnet (якщо контракт вже задеплоєн) або симулюємо в Tenderly fork. Дивимось breakdown по EVM opcodes — де процентно більше всього витрачається.

Ітерації. Застосовуємо зміни по одній, вимірюємо. Slot packing зазвичай дає найбільший ефект — починаємо з нього.

Regression testing. forge snapshot в CI. Будь-який PR, який збільшує gas більше ніж на 1%, вимагає явного обґрунтування в review.

Ориентири по срокам

Аудит газу існуючого контракту + звіт з рекомендаціями: 1-2 дні. Оптимізація з імплементацією змін та тестами: 2-3 дні залежно від складності контракту. Повна переробка storage layout (якщо архітектура спочатку неоптимальна): від 1 тижня, так як вимагає міграційних скриптів для існуючих даних.

Вартість розраховується після аналізу контракту та поточного gas profile.