Tact: язык смарт-контрактов для TON (высокоуровневый и типобезопасный)

Tact — высокоуровневый, статически типизированный язык программирования для смарт-контрактов в сети TON (The Open Network). Его задача — упростить разработку сложных контрактов на TON, дать привычный синтаксис «в стиле TypeScript» и максимально много ошибок ловить ещё на этапе компиляции.

Коротко, чем Tact важен для экосистемы TON:

  • порог входа ниже, чем у FunC/Fift — разработчикам Web2 проще начать писать смарт-контракты;
  • строгая типизация и готовые абстракции по сообщениям, структурам и картам снижают целые классы ошибок;
  • богатый тулчейн: Blueprint, Web IDE, плагины для VS Code/JetBrains, тестирование на TypeScript;
  • язык уже используется в продакшене: DEX’ы, лаунчпады мем-токенов, DeFi-контракты и сервисные протоколы.

Tact: язык смарт-контрактов для TON (высокоуровневый и типобезопасный)

Зачем TON понадобился язык Tact

Исторически смарт-контракты в TON писали на низкоуровневых языках:

Такой стек даёт максимальный контроль и эффективность, но имеет серьёзные минусы:

  • высокий порог входа для обычных бэкенд-разработчиков;
  • сложность чтения и ревью больших контрактов;
  • огромное количество «подводных камней» по сериализации данных, 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.

См. также

Task Runner