Разработка смарт-контрактов на TEAL (Algorand)
Algorand — это не EVM-совместимый чейн, и писать под него «как для Ethereum» не получится. AVM (Algorand Virtual Machine) работает по принципу стека, TEAL — ассемблероподобный язык с жёсткими ограничениями на размер программы и количество операций. Если вы пришли с опытом Solidity, первая реакция на TEAL — удивление. Вторая — уважение к тому, как много можно сделать в рамках этих ограничений.
Специфика AVM, которую нужно понять сразу
TEAL (Transaction Execution Approval Language) — это stack-based язык для Algorand Smart Contracts (ASC1). Программы бывают двух типов: LogicSig (подписывает транзакции без аккаунта) и Application (полноценный stateful смарт-контракт с хранилищем).
Ключевые ограничения AVM 10 (актуальная версия):
| Параметр | Лимит |
|---|---|
| Размер программы (approval + clear) | 8192 байт каждая |
| Глубина стека | 1000 элементов |
| Scratch space | 256 слотов |
| Global state | 64 ключ-значение пары |
| Local state (per account) | 16 ключ-значение пар |
| Box storage (unlimited key-value) | оплата за байты |
| Opcodes за транзакцию | 20 000 (базовый) |
| Opcodes с группой транзакций | до 320 000 |
Лимит в 20 000 opcodes — это не 20 000 строк кода. Один keccak256 стоит 130 opcodes, ed25519verify — 1900. Расчёт бюджета opcodes — обязательная часть разработки сложных контрактов.
PyTeal vs TEAL: когда что использовать
TEAL напрямую — для LogicSig, простых approval программ, финальной оптимизации. Читать и дебажить TEAL проще, чем кажется, если понимаешь стековую модель.
PyTeal — Python-фреймворк, который компилируется в TEAL. Удобен для сложной логики: условия, циклы (через рекурсию), ABI-совместимые контракты. Версия PyTeal 0.20+ поддерживает ARC-4 ABI, что позволяет генерировать контракты с типизированными интерфейсами.
Beaker (надстройка над PyTeal) — даёт более высокоуровневый синтаксис, автоматическую генерацию ABI-схемы, упрощённую работу с state. Используем Beaker для новых проектов, если клиент не ограничен конкретным фреймворком.
Пример структуры simple approval contract на PyTeal:
from pyteal import *
def approval_program():
handle_creation = Seq([
App.globalPut(Bytes("owner"), Txn.sender()),
Approve()
])
is_owner = Txn.sender() == App.globalGet(Bytes("owner"))
handle_optin = Approve()
handle_closeout = Approve()
program = Cond(
[Txn.application_id() == Int(0), handle_creation],
[Txn.on_completion() == OnComplete.OptIn, handle_optin],
[Txn.on_completion() == OnComplete.CloseOut, handle_closeout],
[is_owner, Approve()],
[Int(1), Reject()]
)
return program
Где обычно возникают проблемы
Box storage vs Local/Global state. До AVM 8 разработчики втискивали данные в global state (64 ключа) или local state (16 ключей на аккаунт). С появлением Box storage ограничения сняты — каждый box может хранить до 32 768 байт, количество box-ов не ограничено (только бюджет ALGO за хранение). Не использовать Box storage в новых проектах — архитектурная ошибка.
Группы транзакций (atomic group). В Algorand нельзя вызвать смарт-контракт из другого смарт-контракта в одной транзакции — нет аналога call из EVM. Вместо этого используются grouped transactions: несколько транзакций, атомарно обрабатываемых вместе. Это фундаментальная разница с EVM, которая меняет архитектуру сложных протоколов. DeFi-операция «flash loan → swap → repay» в Algorand — это atomic group из трёх Application Call транзакций, верифицируемых друг через друга через gtxn.
Inner transactions (AVM 6+). Контракт может порождать до 256 inner transactions в одном вызове — трансфер ALGO, ASA, вызов другого приложения. Это основной механизм композируемости в экосистеме. Ошибка — пытаться реализовать что-то через pure stacking без inner transactions, когда задача требует токен-трансфера внутри логики.
ARC-4 и ABI compatibility. Стандарт ARC-4 описывает ABI для Algorand контрактов — типы аргументов, возвращаемые значения, методы. Контракты без ARC-4 сложнее интегрировать с SDK (AlgoKit Utils, algokit-client-generator). Генерируем ABI-схему автоматически через algokit.
Инструменты и стек
- AlgoKit — официальный CLI от Algorand Foundation. Шаблоны проектов, локальная devnet через Docker (AlgoKit LocalNet), деплой, взаимодействие с контрактами.
- algopy (новый Python-фреймворк) — компилируется в TEAL через AVM-компилятор, статическая типизация, более строгий ABI-контроль чем Beaker. Для новых проектов предпочтительнее PyTeal.
- algokit-client-generator — генерирует TypeScript-клиент из ARC-4 JSON-спецификации. Аналог typechain для EVM.
- Algorand Sandbox / AlgoKit LocalNet — локальный нод для разработки.
- Dappflow — веб-интерфейс для инспекции транзакций и state контракта, удобнее чем raw API.
Тестирование пишем на Python (pytest + algokit-utils) для unit-тестов и на TypeScript (Jest + algosdk) для интеграционных. Покрытие coverage через pytest-cov.
Как выглядит разработка
Аналитика (0.5-1 день). Определяем тип контракта (stateful application vs LogicSig), архитектуру state (global/local/box), необходимость inner transactions, совместимость с ARC стандартами (ARC-4, ARC-20 для smart ASA, ARC-200 для ASA-based токенов).
Разработка (2-4 дня). Пишем approval + clear программы. Параллельно — unit-тесты на AlgoKit LocalNet. Проверяем opcode budget на критических путях через debug: true в algod API.
Интеграция. Генерируем ABI JSON, клиент на TypeScript/Python. Тестируем на Algorand Testnet перед mainnet.
Деплой. Application деплоится через ApplicationCreateTxn. Обновляемость — через UpdateApplicationTxn, если approval программа это разрешает. Иммутабельность — через hardcode Int(0) в update/delete хендлерах.
Срок — от 3 до 5 дней для контракта средней сложности. Сложные протоколы с несколькими связанными приложениями и atomic group логикой — до 2 недель.
Типичные ошибки
Не учитывать minimum balance requirement. Каждый аккаунт, который opt-in в application, должен иметь минимум 0.1 ALGO + 0.025 ALGO за каждый local state ключ. Box storage требует 0.0025 ALGO за каждый байт + 0.0025 за ключ. Забывшие об этом контракты ломаются при попытке записи — транзакция откатывается с below min balance.
Смешивать Application Call и Asset Transfer в неправильном порядке. В atomic group порядок транзакций важен. Контракт читает gtxn 0 — это должна быть именно та транзакция, которую вы ожидаете. Путаница в индексах — гарантированный баг при тестировании.
Использовать LogicSig там, где нужен Application. LogicSig подписывает транзакции, но не хранит state. Если логика требует глобального состояния (баланс, счётчик, список адресов) — нужен stateful Application. LogicSig подходит для делегированной авторизации и escrow.







