Tact — высокоуровневый, статически типизированный язык программирования для смарт-контрактов в сети TON (The Open Network). Его задача — упростить разработку сложных контрактов на TON, дать привычный синтаксис «в стиле TypeScript» и максимально много ошибок ловить ещё на этапе компиляции.
Коротко, чем Tact важен для экосистемы TON:
- порог входа ниже, чем у FunC/Fift — разработчикам Web2 проще начать писать смарт-контракты;
- строгая типизация и готовые абстракции по сообщениям, структурам и картам снижают целые классы ошибок;
- богатый тулчейн: Blueprint, Web IDE, плагины для VS Code/JetBrains, тестирование на TypeScript;
- язык уже используется в продакшене: DEX’ы, лаунчпады мем-токенов, DeFi-контракты и сервисные протоколы.
Зачем TON понадобился язык Tact
Исторически смарт-контракты в TON писали на низкоуровневых языках:
- FunC — строгий, близкий к TVM функциональный язык (см. FunC: низкоуровневый язык смарт-контрактов TON);
- Fift — стековый язык и инструмент для низкоуровневой сборки и отладки.
Такой стек даёт максимальный контроль и эффективность, но имеет серьёзные минусы:
- высокий порог входа для обычных бэкенд-разработчиков;
- сложность чтения и ревью больших контрактов;
- огромное количество «подводных камней» по сериализации данных, TVM-инструкциям и газу.
Tact появился как ответ на эти проблемы:
- синтаксис ближе к привычным языкам (TypeScript / современный C-подобный стиль);
- строгая система типов распространяется на всё: хранилище, сообщения, карты, геттеры;
- много инфраструктурных задач (TL-B схемы, сериализация/десериализация, роутинг сообщений) решается «из коробки».
В итоге Tact стал одним из основных способов писать смарт-контракты на TON вместе с FunC и новым языком Tolk.
Ключевые особенности языка Tact
Главные особенности Tact, которые выделяют его на фоне других языков TON:
- Статическая типизация.
Tact — статически типизированный язык. Компилятор проверяет:
- совместимость типов в операциях;
- корректность полей структур и сообщений;
- сигнатуры геттеров и обработчиков.
Множество багов (не тот тип, не то поле, перепутали масштаб монет и т.д.) ловится на этапе компиляции.
- Структуры (struct) и сообщения (message).
Есть отдельные сущности:
- struct — для описания сложных данных в состоянии или результатах геттеров;
- message — для входящих сообщений с автоматическим 32-битным opcode.
Tact сам генерирует TL-B-схемы и код сериализации.
- Карты (map) как базовая структура данных.
Вместо «ручного» построения префикс-деревьев:
- есть тип map
; - синтаксис для инициализации и обновлений;
- методы для чтения/записи/удаления.
- Автоматическая (де)сериализация и роутинг сообщений.
Tact:
- кодирует/декодирует структуры и сообщения в ячейки (cells);
- маршрутизирует внутренние, внешние и bounced-сообщения в нужные обработчики по типу message.
- Traits и переиспользуемое поведение.
Повторяющаяся логика (например, базовый Jetton-кошелёк, ownable-модель или пауза контракта) выносится в trait и подключается в несколько контрактов.
- Низкоуровневый код через asm.
При необходимости можно вставить низкоуровневые фрагменты (TVM-инструкции) напрямую в Tact, не переписывая всё приложение на FunC/Fift.
- Генерация TypeScript-обвязки.
Компилятор Tact умеет генерировать TS-классы:
- типобезопасные вызовы геттеров;
- подготовка и отправка сообщений;
- сериализация структур и карт.
Это упрощает интеграцию с фронтендом и backend-сервисами на TypeScript.
Экосистема и инструменты Tact
Вокруг Tact уже сформировалась полноценная экосистема:
- Документация и «книга языка».
Подробный «Book» с:
- обзором концепций;
- описанием синтаксиса и типов;
- разделом «Cookbook» с типовыми задачами.
- Blueprint (CLI-фреймворк).
Через Blueprint можно:
- создать проект под Tact/FunC/Tolk (см. TON Developer Toolbox);
- собрать структуру contracts/, tests/, scripts/;
- компилировать контракты;
- запускать тесты и деплой-скрипты.
- TON Web IDE.
Веб-IDE позволяет:
- писать Tact-контракты прямо в браузере;
- компилировать и деплоить их в тестнет;
- исследовать структуру контракта, сообщения и геттеры.
- Плагины для редакторов.
Доступны расширения:
- VS Code / VSCodium — подсветка синтаксиса, автодополнение, ошибки компиляции;
- JetBrains (WebStorm, IntelliJ IDEA и др.) через плагины;
- поддержка LSP (Language Server Protocol) для Vim/Neovim и других редакторов.
- Тестовые фреймворки и эмуляторы.
Для Tact-проектов применяют:
- Jest-подобные фреймворки на TypeScript;
- эмуляторы TVM и локальные runtimes для прогонки сценариев;
- отладку с трассировкой сообщений и газ-профилем.
По ощущениям разработчика это ближе к «обычному» backend-стеку, чем классический FunC/Fift, особенно если команда уже работает с TypeScript.
Базовая структура смарт-контракта на Tact
Минимальный контракт на Tact выглядит примерно так (упрощённый пример):
import "@stdlib/deploy";
message Add {
amount: Int;
}
contract Counter with Deployable {
value: Int = 0;
receive(msg: Add) {
self.value += msg.amount;
}
get fun value(): Int {
return self.value;
}
}
Что здесь происходит:
- message Add — описание входящего сообщения с полем amount.
- contract Counter — определение контракта.
- with Deployable — подключение trait’а, который задаёт стандартную схему деплоя.
- value: Int = 0 — поле состояния контракта.
- receive(msg: Add) — обработчик сообщений типа Add; Tact сам маршрутизирует входящие сообщения по их типам.
- get fun value(): Int — геттер, который можно вызывать off-chain без изменения состояния.
Реальные контракты содержат:
- несколько типов сообщений (входящие команды, админские сообщения, служебные ответы);
- сложное состояние (структуры, карты);
- traits (ownable, pausable, Jetton-логика и др.);
- защиту от реентранси и ограничения по правам.
Типы, структуры и сообщения в Tact
В Tact есть набор примитивов, ориентированных на блокчейн и TVM:
- целые числа (Int) с аннотациями хранения (например, как uint32, coins);
- логические значения (Bool);
- строки (String);
- специальные типы: Address, Cell, Slice, Builder и др.
Структуры (struct)
Структуры используются для:
- описания состояния контракта;
- значений, возвращаемых геттерами;
- «пакетов» данных внутри карт.
Пример:
struct UserPosition {
balance: Int as coins;
lastUpdate: Int as uint32;
isFrozen: Bool;
}
Сообщения (message)
Сообщения описывают входящие payload’ы:
message Transfer {
to: Address;
amount: Int as coins;
}
Особенности:
- каждому message соответствует 32-битный opcode;
- opcode может генерироваться автоматически или задаваться явно;
- Tact сам разбирает сообщение и вызывает нужный receive-обработчик.
Это заметно уменьшает количество ручной работы по сравнению с FunC, где роутинг сообщений и сериализация нужно писать руками.
Карты (map) и работа с состоянием
Карты — базовый способ хранить коллекции данных в TON.
Примеры использования:
- map — реестр позиций пользователей;
- map
— индекс по числовым id; - map
— счётчики, ордера, голоса и т. д.
Объявление:
struct Ledger {
positions: map<Address, UserPosition>;
}
Работа с картой:
- positions.get(addr) — получить значение по ключу (может быть null);
- positions.set(addr, pos) — записать/обновить;
- positions.delete(addr) — удалить;
- в некоторых случаях доступны итерации (важно учитывать газ и размер карты).
Важно:
- карты не хранят «длину» по умолчанию — если нужен размер, его лучше считать отдельно или вести отдельный счётчик;
- операции над большими картами могут быть дорогими по газу → стоит проектировать структуру данных так, чтобы избегать длинных циклов.
Цикл разработки на Tact
Типичный рабочий цикл с Tact-контрактом:
- Инициализация проекта.
Через Blueprint создаётся проект:
- конфиги компиляции;
- директории contracts/, tests/, scripts/;
- пример контракта и тестов.
- Проектирование модели данных.
На этой стадии определяют:
- структуру состояния (структуры, карты);
- типы сообщений и геттеров;
- роли (админы, пользователи, сервисы) и модель прав.
- Реализация логики.
Пишется код Tact-контракта:
- обработчики receive для разных сообщений;
- геттеры (get fun) для чтения состояния;
- вспомогательные функции и traits.
- Компиляция и статический анализ.
Компилятор Tact:
- проверяет типы;
- генерирует байткод TVM;
- формирует отчёт со структурами и сообщениями.
- Тестирование.
Сценарии тестирования включают:
- юнит-тесты на TypeScript (инициализация контракта, отправка сообщений, проверка геттеров);
- негативные сценарии (ошибки прав, превышение лимитов, повторные вызовы);
- тесты граничных значений (максимальные суммы, большое количество записей в картах).
- Деплой в тестнет.
С помощью скриптов деплоя контракт разворачивают в тестовой сети TON, прогоняют интеграционные сценарии с реальными кошельками и DApp.
- Релиз в mainnet и мониторинг.
После аудита и стабилизации контракт выкладывают в mainnet. Далее:
- мониторинг транзакций и ошибок;
- сбор метрик (TVL, число пользователей, частота вызовов);
- обновления/миграции (если архитектура это допускает).
Tact и безопасность смарт-контрактов
Tact снижает количество ошибок, но не отменяет потребности в безопасности и аудитах. Частые классы багов:
- Некорректная обработка bounced-сообщений.
В TON возможно, что исходящее сообщение «отскакивает» обратно (bounced). Если это не учесть:
- средства могут «залипать»;
- состояние контракта остаётся неконсистентным.
- Неверные инварианты по балансам.
Даже с типобезопасными coins-полями разработчик может:
- забыть обновить баланс при edge-кейсе;
- разрешить отрицательные значения при неправильной логике.
- Игнорирование газ-ограничений.
Слишком сложные циклы по картам, тяжёлые вычисления и вложенные вызовы могут приводить к:
- out of gas и откатам;
- частично выполненным сценариям.
- Отсутствие явной модели прав.
Если не разнести явно:
- владельца и админов;
- системные роли (оракул, оператор, говернанс);
- права на изменение параметров,
контракт становится уязвим для злоупотреблений.
- Несоблюдение стандартов.
Неверная реализация Jetton/NFT-стандартов:
- ломает совместимость с кошельками и DEX;
- может приводить к «залипанию» токенов.
Рекомендации:
- максимально использовать референс-реализации (Jetton, NFT, базовые либы) вместо полного самописного кода;
- описывать инварианты (в комментариях и в тестах);
- покрывать критичную логику fuzz-тестами;
- проходить аудит для контрактов, которые управляют значимыми объёмами средств — см. AI Security Hub и безопасность смарт-контрактов как общий хаб по безопасности.
Tact vs FunC vs Tolk
В экосистеме TON сейчас де-факто три основных направления языков смарт-контрактов:
- FunC — «каноничный» низкоуровневый язык для контрактов на TVM.
- Tact — высокоуровневый, типобезопасный язык.
- Tolk — ещё один язык более высокого уровня (см. Tolk), но с другим акцентом на синтаксис и модель компиляции.
Сравним по ключевым параметрам.
| Критерий | FunC | Tact | Tolk |
|---|---|---|---|
| Порог входа | Высокий: функциональный стиль, нужно понимать TVM и ячейки | Средний: синтаксис ближе к привычным языкам, хорошая документация | Средний: компактный синтаксис, но меньше материалов |
| Управление памятью/ячейками | Почти всё рукой, много низкоуровневого кода | Сильно абстрагировано, за счёт struct, message, map | Абстракции над TVM, но местами ближе к FunC |
| Типобезопасность | Есть, но много ручной работы | Сильная статическая типизация, генерация TL-B из типов | Сильная типизация, другой подход к структурам |
| Инструменты | Классический тулчейн TON (Fift, low-level-утилиты) | Blueprint, Web IDE, TS-обвязка, плагины для IDE | Поддержка в Blueprint, но экосистема меньше |
| Производительность | Максимальный контроль, минимум абстракций | Немного больше overhead, но обычно приемлемый | Сопоставим с Tact для большинства задач |
Практическая рекомендация:
- для протоколов, где важен максимальный контроль (базовая инфраструктура, эксперименты с TVM) — часто выбирают FunC;
- для большинства DApp (DeFi, игры, сервисные контракты) — Tact даёт лучший баланс читаемости, скорости разработки и надёжности;
- Tolk остаётся хорошим вариантом для команд, которым нравится его синтаксис или есть готовая кодовая база на Tolk.
Типичные сценарии использования Tact
Где Tact особенно удобен:
- DeFi-контракты в TON.
DEX, лаунчпады токенов, лендинги, агрегаторы доходности:
- сложное состояние с картами;
- большое количество сообщений;
- важна скорость разработки и читабельность.
- Jetton и их экосистема.
Реализация токенов по стандартам Jetton:
- минтеры;
- кошельки;
- вспомогательные сервисные контракты.
- Игры и mini-apps в Telegram.
Игровая логика, инвентарь, on-chain прогресс:
- удобно описывать структуры и карты;
- легко интегрировать с TypeScript-бэкендом.
- Сервисные и инфраструктурные контракты.
Регистры, реестры имен, мосты, маршрутизаторы сообщений:
- много структурированных данных;
- важна ясная модель прав и геттеров.
Для низкоуровневых экспериментов (нестандартные модели хранения, особые инструкции TVM) иногда всё ещё предпочтительнее FunC/Fift, но Tact при этом позволяет вставить asm-фрагменты и не терять в контроле.
Как начать работать с Tact разработчику
Базовый checklist, если вы хотите перейти на Tact:
- Установить:
- Blueprint и инструменты из TON Developer Toolbox;
- расширение для любимой IDE (VS Code / JetBrains).
- Прочитать:
- официальную «книгу Tact»;
- разделы по структурам, сообщениям и картам;
- лучшие практики по Jetton и стандартам.
- Собрать:
- простой контракт (Counter, Vault, простой Jetton-минтер);
- юнит-тесты с TypeScript-обвязкой.
- Потрогать:
- деплой в тестнет;
- интеграцию с реальным TON-кошельком;
- вызовы геттеров и отправку сообщений.
После этого можно переходить к более сложным протоколам: DEX, стейкинг, игры и т. д.
FAQ по языку Tact
Tact заменит FunC или это просто ещё один язык? Tact не «убивает» FunC. Скорее:
- FunC остаётся низкоуровневым «языком ядра»;
- Tact — высокоуровневый язык поверх TVM, который закрывает огромный пласт задач (DApp, DeFi, игры).
Команда может комбинировать языки: часть контрактов на FunC, часть — на Tact.
Насколько безопасен Tact по сравнению с FunC? Tact:
- снижает вероятность ряда ошибок за счёт типизации и абстракций;
- делает код более читаемым и ревьюабельным.
Но:
- всё равно возможны логические баги;
- необходимы тесты, аудит и хорошая модель прав.
Язык — не гарантия безопасности, но хороший инструмент.
Есть ли потери в производительности из-за Tact? Любой высокоуровневый язык добавляет слой абстракций. На практике:
- для большинства приложений overhead не критичен;
- «узкие места» можно оптимизировать или реализовать через asm/FunC;
- удобство разработки обычно важнее небольшой экономии газа.
Можно ли мигрировать существующий FunC-контракт на Tact? Прямого «автоматического» переноса нет:
- логику придётся перепроектировать под абстракции Tact;
- часть кода можно вынести в asm/FunC и вызывать из Tact.
Зато в результате код становится более читаемым и легче поддерживается.
Подходит ли Tact новичкам в блокчейне? Да, если:
- уже есть опыт в TypeScript/современных языках;
- вы готовы разобраться с концепциями TON (TVM, сообщения, ячейки).
Tact делает порог входа ниже, чем FunC/Fift, но требует базового понимания того, как работает блокчейн TON.
