Интеграция кошелька с Tonkeeper (TON)
TON Connect — это не просто «подключить кошелёк». Протокол принципиально отличается от EVM: нет прямого JSON-RPC, соединение работает через relay-сервер (bridge), а кошелёк (в том числе Tonkeeper) взаимодействует через deep links или QR-код. Если пробовать перенести EVM-опыт на TON без понимания этой модели, получится неработающая интеграция.
TON Connect 2.0: как устроено соединение
Dapp инициирует сессию: генерирует keypair (x25519), публикует свой публичный ключ на bridge-сервере (bridge.tonapi.io или self-hosted). Кошелёк получает invite через deep link (ton-connect://...) или QR. После handshake — зашифрованный канал через bridge. Все запросы (sendTransaction, signMessage) идут через этот канал, не через прямой RPC к ноде.
Это значит: интеграция работает даже если нода TON недоступна — bridge держит соединение с кошельком отдельно от чтения блокчейна.
Реализация на @tonconnect/ui-react
Официальная библиотека покрывает большинство кейсов:
import { TonConnectUIProvider, TonConnectButton, useTonConnectUI, useTonAddress } from '@tonconnect/ui-react';
// В корне приложения
<TonConnectUIProvider manifestUrl="https://yourapp.com/tonconnect-manifest.json">
<App />
</TonConnectUIProvider>
manifest.json — обязательный файл, который кошелёк показывает пользователю при подключении:
{
"url": "https://yourapp.com",
"name": "Your dApp",
"iconUrl": "https://yourapp.com/icon-256.png"
}
Файл должен быть доступен по HTTPS на указанном URL. Без корректного манифеста Tonkeeper откажет в подключении.
Отправка транзакции:
const [tonConnectUI] = useTonConnectUI();
const userAddress = useTonAddress(); // raw или friendly format
async function sendTon(toAddress: string, amountNano: string) {
await tonConnectUI.sendTransaction({
validUntil: Math.floor(Date.now() / 1000) + 300, // 5 минут
messages: [
{
address: toAddress,
amount: amountNano, // в nanoTON (1 TON = 1e9 nanoTON)
}
]
});
}
Взаимодействие со смарт-контрактами
TON контракты принимают сообщения с body — TL-B cell. Для отправки call на Jetton контракт (аналог ERC-20):
import { beginCell, toNano } from '@ton/core';
// Transfer Jetton: op = 0xf8a7ea5
const body = beginCell()
.storeUint(0xf8a7ea5, 32) // op code
.storeUint(0, 64) // query_id
.storeCoins(toNano('10')) // amount
.storeAddress(destinationAddress)
.storeAddress(responseAddress)
.storeBit(0) // no custom payload
.storeCoins(toNano('0.05')) // forward_ton_amount
.storeBit(0)
.endCell();
await tonConnectUI.sendTransaction({
validUntil: Math.floor(Date.now() / 1000) + 300,
messages: [{
address: jettonWalletAddress,
amount: toNano('0.1').toString(), // TON для газа
payload: body.toBoc().toString('base64'),
}]
});
Получение адреса и баланса
Чтение данных — через TonAPI или toncenter.com, не через TON Connect:
import { TonClient, Address } from '@ton/ton';
const client = new TonClient({
endpoint: 'https://toncenter.com/api/v2/jsonRPC',
apiKey: process.env.TONCENTER_API_KEY,
});
const balance = await client.getBalance(Address.parse(userAddress));
useTonAddress() возвращает адрес в двух форматах: raw (0:abcd...) и friendly (base64url, bounce/non-bounce). Для отображения — friendly. Для сравнения в коде — raw или нормализованный через Address.parse().toString().
Ориентиры по срокам
Базовая интеграция TON Connect (подключение + отправка TON) — полдня. С поддержкой Jetton transfers и чтением балансов — 1-2 дня. Полноценный кошелёк-экран с историей транзакций через TonAPI — 2-3 дня.







