Настройка приема платежей в TON

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1Все 1306 услуг
Настройка приема платежей в TON
Простой
~2-3 дня
Часто задаваемые вопросы

Направления блокчейн-разработки

Этапы блокчейн-разработки

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1307
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1219
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    920
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1147
  • image_logo-advance_0.webp
    Разработка логотипа компании B2B Advance
    610
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    885

Настройка приёма платежей в TON

TON — не Ethereum с другим RPC. Главная особенность, которая ломает интуицию: транзакции асинхронны и имеют древовидную структуру. Когда пользователь отправляет TON на ваш адрес, это одна транзакция. Когда отправляет Jetton (USDT на TON, например) — это цепочка из трёх сообщений: transfer → internal message → notification. Мониторинг должен учитывать это.

Два сценария: нативный TON и Jetton (USDT/USDC)

Приём нативного TON

Самый простой случай. Генерируем уникальный адрес или используем один адрес с comment (memo) для идентификации платежа — TON нативно поддерживает текстовые комментарии в транзакциях.

Мониторинг через TON Center API или TonAPI:

import { TonClient } from '@ton/ton';
import { Address } from '@ton/core';

const client = new TonClient({
  endpoint: 'https://toncenter.com/api/v2/jsonRPC',
  apiKey: process.env.TONCENTER_API_KEY,
});

async function checkIncomingTransactions(
  address: string,
  lastLt: string // last known logical time
) {
  const addr = Address.parse(address);
  const transactions = await client.getTransactions(addr, {
    limit: 20,
    lt: lastLt,
    archival: false,
  });

  for (const tx of transactions) {
    // Только входящие, не bounce
    if (tx.inMessage && tx.inMessage.info.type === 'internal') {
      const info = tx.inMessage.info;
      const value = info.value.coins; // в nanoTON
      const comment = tx.inMessage.body; // текстовый комментарий
      
      // Матчим комментарий с нашим payment ID
      console.log(`Received: ${value} nanoTON, comment: ${comment}`);
    }
  }
}

Важно: проверяем bounce флаг и bounced флаг. Bounced транзакция означает, что получатель вернул средства — её не нужно засчитывать как оплату.

Приём Jetton (USDT, USDC, NOT и др.)

Jetton Transfer работает иначе: пользователь отправляет сообщение своему JettonWallet контракту, который шлёт внутреннее сообщение к JettonWallet получателя, а тот отправляет transfer_notification на адрес получателя.

Чтобы получать уведомления о Jetton переводах, в параметрах forward_ton_amount и forward_payload нужно указать сумму TON для уведомления и данные:

transfer_notification#7362d09c
  query_id: uint64
  amount: coins        // количество Jetton
  sender: MsgAddress   // адрес отправителя
  forward_payload: ^Cell  // наш custom payload (payment ID)

Для приёма Jetton на сервере нужно мониторить не основной адрес, а JettonWallet нашего адреса:

// Получаем адрес нашего JettonWallet для USDT
async function getJettonWalletAddress(
  ownerAddress: string,
  jettonMasterAddress: string
): Promise<string> {
  const master = client.open(
    JettonMaster.create(Address.parse(jettonMasterAddress))
  );
  const walletAddr = await master.getWalletAddress(
    Address.parse(ownerAddress)
  );
  return walletAddr.toString();
}

// USDT на TON mainnet
const USDT_MASTER = 'EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs';

Уникальные адреса vs comment-based идентификация

Подход 1: Comment/Memo идентификация

Один адрес для всех платежей, пользователь указывает уникальный comment (payment ID). Просто в реализации, но требует обязательного UX — объяснить пользователю необходимость комментария. Ошибка пользователя = потерянный платёж (нужен manual reconciliation).

Подход 2: Уникальный адрес на каждый платёж

Генерируем HD wallet адреса (TON поддерживает стандартные мнемоники BIP39 + нестандартную деривацию). Каждый заказ — отдельный адрес. Никаких комментариев, нет ошибок пользователя, простой мониторинг.

import { mnemonicToPrivateKey } from '@ton/crypto';
import { WalletContractV4 } from '@ton/ton';

async function derivePaymentAddress(
  masterMnemonic: string[],
  orderIndex: number
): Promise<string> {
  // TON не стандартный BIP44, используем разные subwalletId
  const keyPair = await mnemonicToPrivateKey(masterMnemonic);
  const wallet = WalletContractV4.create({
    publicKey: keyPair.publicKey,
    workchain: 0,
    walletId: 698983191 + orderIndex, // уникальный subwalletId
  });
  return wallet.address.toString({ bounceable: false });
}

Минус: нужно периодически сводить средства с дочерних адресов на основной (consolidation sweep).

Polling vs Webhook

TON Center API поддерживает webhook подписки на транзакции по адресу — это удобнее polling. TonAPI (tonapi.io) — более богатый API с WebSocket стримингом.

Для self-hosted варианта: TON node (C++ или Go реализация) с собственным индексатором. Но это существенно сложнее — нода занимает ~2TB и требует синхронизации несколько дней.

Для большинства проектов: TonAPI с WebSocket + polling как fallback с cursor по lt (logical time).

Confirmation

В TON нет понятия "количество подтверждений" как в Bitcoin. Транзакция либо включена в блок и финальна, либо нет. TON использует BFT-подобный консенсус — finality достигается в течение нескольких секунд после включения в блок. Практически: достаточно дождаться 1 блока (~5 секунд) и проверить, что транзакция не bounce.

Тестирование

TON Testnet — отдельная сеть. Testnet TON получаем через бот @testgiver_ton_bot. API endpoint: https://testnet.toncenter.com/api/v2/jsonRPC. Для разработки также полезен Sandbox от Blueprint — локальный TVM эмулятор без обращения к сети.