Learning Platform
Глоссарий Troubleshooting
Урок 03.06 · 15 мин
Средний
Anti-patternsCommon MistakesBest PracticesArchitecture Review

Архитектурные Anti-patterns на TON

Anti-pattern 1: Монолитный контракт

Ошибка: Один контракт хранит все данные и всю логику приложения.

[NO] Монолит:
TokenContract:
  - mapping: 1M пользователей → балансы
  - все transfers → одна точка обработки
  - storage fee за 1M записей → огромная

[OK] Sharded (Jetton pattern):
MasterContract: supply, metadata
WalletContract_1: баланс user_1
WalletContract_2: баланс user_2
...
WalletContract_N: баланс user_N

Проблема: Монолитный контракт = один шард = bottleneck. Все транзакции обрабатываются последовательно. Storage fee растёт пропорционально числу пользователей.

Решение: Sharded pattern — данные каждого пользователя в отдельном контракте. Шарды обрабатывают их параллельно.

Anti-pattern 2: Синхронное мышление

Ошибка: Проектировать как Ethereum — ожидать мгновенный ответ от другого контракта.

[NO] Синхронное мышление:
function swap(tokenA, tokenB, amount) {
  balance = tokenA.balanceOf(msg.sender);  // ← Это невозможно на TON!
  tokenA.transferFrom(msg.sender, amount);  // ← Нельзя вызвать и ждать результат
  tokenB.transfer(msg.sender, computed_amount);
}

[OK] Асинхронное:
// Шаг 1: User → DEX: "хочу swap" + отправляет Token A
recv_internal(msg) {
  if (op == op::swap_request) {
    // Сохранить pending swap в state
    save_pending_swap(sender, amount, min_output);
    // Отправить запрос на проверку баланса (async)
    send(jetton_wallet, op::transfer, amount, dex_address);
  }
}

// Шаг 2: DEX получает Token A → рассчитывает → отправляет Token B
recv_internal(msg) {
  if (op == op::transfer_notification) {
    // Token A получен, рассчитать курс
    output = calculate_output(received_amount);
    // Отправить Token B пользователю (ещё один async message)
    send(tokenB_wallet, op::transfer, output, user_address);
  }
}

Проблема: На TON нет synchronous calls. Каждое взаимодействие — async message. Попытка «вызвать и ждать» приведёт к design, который не может работать.

Anti-pattern 3: Игнорирование bounce

Ошибка: Отправлять сообщения без обработки bounce, надеясь, что всё пройдёт.

[NO] Без bounce handler:
send(recipient, value, body, mode);
// Если recipient не существует или бросил исключение
// → средства потеряны навсегда

[OK] С bounce handler:
send(recipient, value, body, mode | SEND_BOUNCE);

recv_internal(msg) {
  if (msg.bounced) {
    // Обработать ошибку: вернуть средства, обновить state
    refund(original_sender);
  }
}

Проблема: Без bounce handler — lost funds. Это самая дорогая ошибка на TON.

Anti-pattern 4: Unbounded storage

Ошибка: Контракт хранит неограниченно растущие данные (логи, история, все ордера).

[NO] Unbounded:
// Каждый swap добавляет запись в историю
self.history.push(swap_record);
// storage fee растёт → контракт "голодает" → freeze

[OK] Bounded:
// Хранить только последние N записей или агрегаты
self.total_volume += amount;
self.total_swaps += 1;
// Полная история — в off-chain indexer

Проблема: Storage fee пропорционально размеру state. Unbounded growth = контракт со временем потеряет весь баланс на storage fees и будет заморожен.

Anti-pattern 5: Hardcoded gas values

Ошибка: Жёстко закодированные значения gas forward.

[NO] Hardcoded:
send(target, ton("0.05"), body, mode);
// Что если 0.05 TON недостаточно для обработки?
// Что если gas prices изменятся?

[OK] Dynamic:
// Рассчитать gas на основе текущих conditions
int fwd_fee = get_forward_fee(cells, bits);
int compute_fee = estimated_compute();
int total = fwd_fee + compute_fee + SAFETY_MARGIN;
send(target, total, body, mode);

Проблема: Gas prices могут меняться через network config update. Hardcoded values сломаются.

Чек-лист архитектурного ревью

Anti-pattern Severity: Architecture Review Checklist
Critical: Sharding
Critical: Async Design
Critical: Bounce Handling
Critical: Access Control
High: Storage Bounds
High: Gas Forward
High: Replay Protection
High: Integer Overflow

Перед деплоем системы проверьте:

КатегорияПроверкаКритичность
ShardingКонтракты sharding-friendly? Нет монолитов?Critical
AsyncMessage flow корректен? State machine для multi-step?Critical
BounceВсе messages с bounce:true? Bounce handlers есть?Critical
StorageState bounded? Storage fee рассчитан?High
GasGas forward достаточен? Не hardcoded?High
Replayquery_id для идемпотентности?High
AccessТолько authorized senders?Critical
OverflowInteger overflow проверки?High
Проверка знанийKnowledge check
ОтветAnswer

Проверьте понимание

Результат: 0 из 0
Аналитический
Вопрос 1 из 3. Контракт хранит историю всех swap-ов (unbounded list). Через год у контракта закончился баланс. Что произошло?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 8