Learning Platform
Глоссарий Troubleshooting
Урок 04.02 · 20 мин
Средний
Message FlowGas ForwardingMessage ChainOrdering

Message Flow Design

Проектирование цепочек сообщений

На TON каждая сложная операция — это цепочка сообщений между контрактами. Проектирование этих цепочек — ключевой навык TON System Design.

Пример: Jetton Transfer

Простейшая операция — перевод Jetton токена — уже требует 3 сообщения:

Jetton Transfer: 3 сообщения
User
Sender Wallet
Sender Wallet
Receiver Wallet
Receiver Wallet
Receiver Owner
Jetton Transfer Flow:
1. User → external msg → Sender Jetton Wallet: "transfer 100 tokens to Bob"
2. Sender Wallet → internal msg → Receiver Wallet: "internal_transfer(100, from=Alice)"
3. Receiver Wallet → internal msg → Bob: "transfer_notification(100, from=Alice)"

Gas flow:
User отправляет ~0.1 TON → Sender Wallet забирает gas → forward остаток →
→ Receiver Wallet забирает gas → forward остаток → Bob

Правила проектирования message flows

Правило 1: Рассчитайте gas для всей цепочки

Начальное сообщение должно содержать достаточно TON для всех hop-ов:

Total gas = gas_step_1 + fwd_fee_1 + gas_step_2 + fwd_fee_2 + ... + safety_margin

Правило 2: Каждый контракт отвечает за forward

Контракт получает сообщение с value → использует часть для compute → forward остаток:

recv_internal(msg) {
  int my_gas = 10_000_000;  // ~0.01 TON для compute
  int remaining = msg.value - my_gas;
  
  // Forward оставшийся value следующему в цепочке
  send(next_contract, remaining, body, SEND_MODE_PAY_FEES_SEPARATELY);
}

Правило 3: Терминальный контракт возвращает excess

Последний контракт в цепочке должен вернуть неиспользованный gas отправителю:

// Последний контракт — вернуть excess
int excess = msg.value - compute_fee - storage_fee;
if (excess > MIN_RETURN_AMOUNT) {
  send(original_sender, excess, "excess", SEND_MODE_IGNORE_ERRORS);
}

Gas Forwarding Strategies

Strategy 1: Fixed Gas Forward

send(target, ton("0.05"), body, mode);
  • Простой
  • Может быть недостаточно / слишком много
  • Не адаптируется к gas price changes

Strategy 2: Percentage Forward

int forward = msg.value * 80 / 100;  // 80% вперёд
send(target, forward, body, mode);
  • Адаптивный
  • На длинных цепочках значение уменьшается экспоненциально

Strategy 3: Calculated Forward (рекомендуется)

int fwd_fee = get_forward_fee(cells, bits, is_masterchain);
int compute_fee = GAS_ESTIMATE * gas_price;
int forward = fwd_fee + compute_fee + SAFETY_MARGIN;
send(target, forward, body, mode);
  • Точный
  • Адаптируется к network conditions
  • Сложнее в реализации

Ordering Guarantees

Intra-shard ordering

Сообщения между контрактами в одном шарде доставляются в порядке отправки (FIFO).

Cross-shard ordering

Между разными шардами порядок не гарантирован:

Contract A отправляет:
  msg1 → Contract B (shard X)
  msg2 → Contract C (shard Y)

Возможные порядки обработки:
  [OK] msg1, msg2
  [OK] msg2, msg1  ← тоже возможно!
WARNING

Проектируйте для out-of-order

Если ваша логика зависит от порядка обработки сообщений разными контрактами — перепроектируйте. Используйте state machine с явными состояниями вместо implicit ordering.

Паттерн: Request-Response

Когда нужно получить данные от другого контракта:

// Contract A: отправить запрос
send(contractB, gas, {op: op::get_price, query_id: 123}, bounce: true);
// Сохранить pending запрос в state
self.pending_queries[123] = {callback: process_swap, ...};

// Contract B: обработать запрос и ответить
recv_internal(msg) {
  if (op == op::get_price) {
    int price = calculate_price();
    send(msg.sender, excess, {op: op::price_response, query_id, price}, bounce: false);
  }
}

// Contract A: обработать ответ
recv_internal(msg) {
  if (op == op::price_response) {
    let pending = self.pending_queries[msg.query_id];
    pending.callback(msg.price);
    delete self.pending_queries[msg.query_id];
  }
}
Проверка знанийKnowledge check
ОтветAnswer

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

Результат: 0 из 0
Прикладной
Вопрос 1 из 2. Jetton transfer на TON требует 3 сообщения: User→SenderWallet→ReceiverWallet→ReceiverOwner. Пользователь отправляет 0.1 TON для gas. Почему может не хватить?

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

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

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

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