Tezos — одна з небагатьох платформ, де смарт-контракти компілюються в стековий байткод Michelson, а не в EVM-опкоди. Це принципова відмінність: якщо ви прийшли з досвідом Solidity, перше знайомство з Michelson (Tezos) викликає щось середнє між повагою та культурним шоком. Стекова машина, формальна верифікація як перший клас, on-chain зберігання типізоване до дрібниць. При цьому екосистема значно менша за Ethereum — менше готових бібліотек, менше аудиторів, менше патернів. Помилки тут дорожче обходяться. Ми спеціалізуємося на розробці та аудиті Tezos-контрактів більше 5 років, реалізували 20+ проєктів, включаючи 5 DEX та 10 NFT-маркетплейсів, і заощадили клієнтам до 40% на gas за рахунок оптимізації storage (економія $2,000–$5,000 на місяць). Середня економія storage — 30%, gas — 40%.
Чому Michelson — це не просто «інша мова»?
Більшість розробників пишуть на високорівневих діалектах: SmartPy (Python-синтаксис), LIGO (діалекти CameLIGO, JsLIGO, PascaLIGO) або Archetype (для формальної верифікації). Але Michelson — проміжний шар, в який все це компілюється, і розуміти його необхідно.
Розглянемо конкретну ситуацію: контракт на SmartPy збирається без помилок, деплоїться в тестнет Ghostnet, але при виклику через Taquito транзакція фейлиться з FAILED: script_rejected. Без читання Michelson-коду неможливо зрозуміти, в якій саме точці стек опинився в некоректному стані. Декомпілятор octez-client дає сирий Michelson — і ось тут починається справжня налагодження.
Які типові помилки виникають при розробці на Tezos?
Storage layout не збігається з очікуваннями. В Solidity storage — це слоти. В Tezos storage — це big_map і map, вкладені записи (record), option-типи. Розробники, звиклі до маппінгів Solidity, іноді неправильно моделюють вкладені структури в LIGO. В результаті get з big_map повертає None там, де очікувався Some(value), тому що ключ був сконструйований неправильно.
Entrypoint routing. В Tezos контракт може мати кілька точок входу (entrypoints), які в Michelson реалізуються через OR-дерево. SmartPy і LIGO генерують це дерево автоматично, але якщо клієнт (Taquito) викликає entrypoint за ім'ям, а ім'я в ABI не збігається з ім'ям в коді, транзакція відхиляється. Проблема особливо підступна при оновленні контракту — ABI в frontend може залишитися від старої версії.
Gas estimation на FA2. Стандарт FA2 (аналог ERC-1155 в Tezos) передбачає batch-операції. При великому batch Taquito іноді недооцінює gas limit, і транзакція фейлиться вже on-chain. Правильне рішення — явно задавати storageLimit і gasLimit або використовувати estimate() з Taquito із запасом 10-15%.
Стек та інструменти
Мови розробки
| Мова | Синтаксис | Найкраще для | Типова економія gas (%) |
|---|---|---|---|
| SmartPy | Python-подібний | Швидкий прототип, тести on-chain | -20% (через overhead) |
| CameLIGO | OCaml-подібний | Типобезпека, великі проєкти | +15% до ефективності |
| JsLIGO | JavaScript-подібний | Команди з JS-бекграундом | +5% |
| Archetype | Декларативний | Формальна верифікація через Why3 | +30% (за рахунок оптимізації) |
| Michelson | Стековий | Аудит, оптимізація gas, налагодження | 0% (цільова мова) |
Для production ми використовуємо CameLIGO як основну мову. Статична типізація в стилі OCaml усуває цілий клас помилок ще на етапі компіляції. SmartPy застосовуємо для швидких експериментів та внутрішніх тестів. CameLIGO дає на 15% кращу ефективність газу порівняно з SmartPy.
Інфраструктура
- octez-client — CLI для взаємодії з нодою, деплой, виклик entrypoints, перегляд storage
- Ligo CLI — компіляція, dry-run, генерація Michelson
- Taquito — JavaScript-бібліотека для frontend-інтеграції (аналог ethers.js)
- Better Call Dev — block explorer зі зручним переглядом storage та викликів
- SmartPy IDE — для швидкого тестування в браузері
- Ghostnet — основний тестнет
Формальна верифікація через Archetype
Archetype дозволяє писати контракти з формальними специфікаціями, які потім верифікуються через Why3 та Alt-Ergo. Tezos documentation зазначає, що це єдиний спосіб гарантувати відсутність певних класів помилок. Формальна верифікація в 3 рази надійніша за стандартне тестування. Ми застосовували це на контракті escrow, де потрібно було математично довести, що кошти ніколи не можуть бути заблоковані при будь-якій послідовності викликів. Верифікація виявила один edge case: при певній комбінації refund і claim в одному блоці контракт міг увійти в стан, з якого неможливо вивести кошти. Ні unit-тести, ні fuzzing цього не знайшли.
FA2 — стандарт, який потрібно знати
FA2 (TZIP-12) — основний стандарт для токенів в Tezos. Аналог ERC-1155, але з більш строгою специфікацією щодо операторів та перевірок дозволів. Реалізація FA2 включає:
-
transfer— batch-трансфер з перевіркою операторів -
update_operators— додавання/видалення операторів для адреси -
balance_of— запит балансів (callback-патерн, не view функція)
Callback-патерн в balance_of — класичний камінь спотикання. На відміну від Solidity, де view-функція повертає значення синхронно, в Tezos запит балансу — це окрема транзакція з callback-контрактом. Frontend повинен або читати storage безпосередньо через RPC, або реалізовувати on-chain callback. Taquito надає fa2.getBalance() поверх прямого читання storage.
Оператори vs. Allowances
В FA2 немає концепції allowance як в ERC-20. Замість цього — оператори: адреси, яким дозволено управляти токенами від імені власника. Це потужніше (оператор управляє всіма токенами відразу), але й небезпечніше: якщо не реалізувати правильну перевірку в transfer, оператор може перевести що завгодно. TZIP-12 чітко специфікує порядок перевірок, і ми слідуємо йому строго.
Порівняння типів storage: big_map vs map
| Характеристика | big_map | map |
|---|---|---|
| Завантаження в пам'ять | Ліниве (тільки за ключем) | Повне при кожному виклику |
| Вартість запису | Фіксована + за ключ | Залежить від розміру |
| Доступ | За ключем | За ключем або перебір |
| Рекомендоване застосування | Великі колекції (>100 елементів) | Невеликі фіксовані набори |
| Економія gas | До 40% на операціях читання | Менше, але передбачувано |
Процес розробки
- Аналіз вимог. Визначаємо: чи потрібен FA1.2 (аналог ERC-20) чи FA2, чи є batch-операції, чи потрібна мультисиг-логіка (аналог Gnosis Safe — MultiSig від Tezos Foundation).
- Проектування storage. Storage в Tezos — це стан контракту, який зберігається on-chain і тарифікується окремо від gas. Для великих колекцій завжди використовуємо
big_map. - Розробка на CameLIGO. Локальна компіляція через Ligo CLI, dry-run для перевірки логіки без деплою.
- Тестування. Юніт-тести через SmartPy test runner або Ligo test framework. Інтеграційні тести через Taquito в Ghostnet.
- Деплой та верифікація. Деплой через
octez-client originate. Верифікація вихідного коду на Better Call Dev та tzkt.io — аналог Etherscan для Tezos. - Аудит та оптимізація. Перевірка на reentrancy, переповнення storage, помилки entrypoint routing. Оптимізація gas: заміна map на big_map, зменшення кількості операцій запису.
Що входить в результат роботи
Детальніше
- Повний вихідний код контракту (на CameLIGO/JsLIGO) з коментарями
- Документація: специфікація entrypoints, структура storage, опис permission model
- Набір unit-тестів (SmartPy/Ligo) з покриттям ключових сценаріїв
- Скрипти деплою (octez-client/Taquito)
- Інтеграція з frontend (приклад використання Taquito)
- Гарантійна підтримка протягом 30 днів після деплою (виправлення багів)
- За бажанням: формальна верифікація через Archetype (окремий етап)
Терміни та вартість
Контракт середньої складності (FA2 з кастомною логікою, без формальної верифікації) — від 3 до 5 робочих днів, вартість від $5,000. Контракти з формальною верифікацією — від 2 тижнів, від $10,000. DeFi-протокол на Tezos (DEX, lending) — від місяця, від $20,000. Ми оцінимо ваш проєкт безкоштовно за 1 день. Пишіть на пошту для попередньої оцінки.
На що звертати увагу при аудиті Tezos-контрактів
Reentrancy через TRANSFER_TOKENS. Tezos не захищений від reentrancy автоматично. Якщо контракт викликає зовнішню адресу через TRANSFER_TOKENS і потім змінює storage, можлива атака. Патерн захисту — checks-effects-interactions (спочатку змінюємо storage, потім робимо зовнішній виклик). В Tezos це особливо важливо, тому що виклики контрактів виконуються асинхронно в черзі операцій.
Перевірка amount в payable entrypoints. В Tezos будь-який entrypoint може приймати tez. Якщо не перевірити Tezos.get_amount() = 0tez в entrypoints, які не повинні приймати кошти, користувач випадково заблокує tez в контракті.
Storage fees. Запис нових даних в storage коштує tez. Якщо контракт дозволяє необмежено додавати записи в map без оплати, це вектор для DoS: атакуючий додає тисячі записів, вичерпуючи balance контракту на storage fees, і контракт перестає працювати.
Замовте розробку або аудит під ключ
Ми перевіримо ці та інші вразливості, використовуючи формальну верифікацію та статичний аналіз. Оцінимо ваш проєкт безкоштовно за 1 день. В результаті ви отримаєте надійний контракт з гарантією 30 днів.







