Пошаговый гайд для Unity разработчиков об интеграции протокола Ton Connect 2.0 в свои проекты.
В рамках данной статьи будет рассмотрена библиотека Uniton Connect, с помощью которой можно быстро реализовать подключение TON кошельков и отправку транзакций.
Для её использования необходимо иметь активный TON кошелёк. Здесь подойдёт абсолютно любой, например - TG Wallet, Tonkeeper или MyTonWallet.
Установка библиотеки
В данный момент времени, библиотека не поддерживает установку через указание git ссылки в Package Manager. Поэтому переходим во вкладку Releases и скачиваем .unityPackage с актуальной версией.
После загрузки пакета, можно создать новый Unity проект под платформу WebGL для тестов или добавить в свой текущий проект. В самой библиотеке есть готовая демо сцена со всем доступным функционалом, поэтому подойдёт даже 1 вариант. Далее необходимо импортировать либу и можно приступать к её инициализации.
Инициализация библиотеки
Сперва создайте новую сцену (или откройте существующую) и добавьте новый GameObject. Теперь необходимо прикрепить на него скрипт UnitonConnectSDK.cs, который содержит необходимый функционал библиотеки.
Затем ставим галочку TestMode, дабы на данном этапе не заморачиваться с настройкой манифеста вашего dApp.

Ну а теперь можно создать новый MonoBehaviour скрипт, в котором начинаем описывать логику инициализации:
using UnityEngine;
using UnitonConnect.Core;
public sealed class InitExample: MonoBehaviour
{
private UnitonConnectSDK _unitonConnect;
private void OnDisable()
{
_unitonConnect.OnInitiliazed -= SdkInitialized;
}
private void Start()
{
_unitonConnect = UnitonConnectSDK.Instance;
_unitonConnect.OnInitiliazed += SdkInitialized;
_unitonConnect.Initialize();
}
private void SdkInitialized(bool isSuccess)
{
if (isSuccess)
{
Debug.Log("Sdk has been successfully initialized");
}
}
}
P.S: Стоит отметить, что само ядро библиотеки базируется на фреймворке Ton Connect UI. Поэтому указанный код попросту не будет работать в редакторе Unity и для этого нужно сделать билд под WebGL - к этому перейдём чуть позже, чтобы функционал можно было протестировать.
Подключение/отключение TON кошелька
После успешной инициализации, можно перейти к работе с самим кошельком. В первую очередь, создайте и разместите 2 кнопки на сцене внутри канваса и текстовое поле, где будет отображаться адрес подключенного кошелька (можно использовать Legacy Text или TextMeshPro - разницы тут нет).
Теперь создаём новый скрипт, который будет отвечать за взаимодействие с кошельком:
using UnityEngine;
using UnityEngine.UI;
using UnitonConnect.Core;
public sealed class WalletInteractExample: MonoBehaviour
{
[SerializeField, Space] private Text _addressBar;
[SerializeField, Space] private Button _connectButton;
[SerializeField] private Button _disconnectButton;
private UnitonConnectSDK _unitonConnect;
private void OnDisable()
{
_connectButton.onClick.RemoveListener(Connect);
_disconnectButton.onClick.RemoveListener(Disconnect);
_unitonConnect.OnWalletConnected -= WalletConnected;
_unitonConnect.OnWalletDisconnected -= WalletDisconnected;
_unitonConnect.OnWalletConnectFailed -= WalletConnectFailed;
}
private void Start()
{
_connectButton.onClick.AddListener(Connect);
_disconnectButton.onClick.AddListener(Disconnect);
_disconnectButton.interactable = false;
_unitonConnect = UnitonConnectSDK.Instance;
_unitonConnect.OnWalletConnected += WalletConnected;
_unitonConnect.OnWalletDisconnected += WalletDisconnected;
_unitonConnect.OnWalletConnectFailed += WalletConnectFailed;
}
private void Connect()
{
if (!_unitonConnect.IsInitialized)
{
return;
}
_unitonConnect.Connect();
}
private void Disconnect()
{
if (!_unitonConnect.IsInitialized)
{
return;
}
_unitonConnect.Disconnect();
}
private void WalletConnected(WalletConfig wallet)
{
var userAddress = wallet.Address;
var shortAddress = _unitonConnect.Wallet.ToShort(6);
_addressBar.text = shortAddress;
_connectButton.interactable = false;
_disconnectButton.interactable = true;
}
private void WalletDisconnected(bool isSuccess)
{
if (isSuccess)
{
_addressBar.text = string.Empty;
_connectButton.interactable = true;
_disconnectButton.interactable = false;
}
}
private void WalletConnectionFailed(string errorMessage)
{
Debug.LogError("Failed to connect wallet, reason: {errorMessage}");
}
}
Ну вот, мы завершили реализацию логики подключения/отключения TON кошелька и всё это сделано, буквально, в пару строк. Теперь можно перейти к тестовой сборке проекта, чтобы наглядно увидеть результат.
Настройка конфигурации сборки и билд
Перед началом самой сборки, необходимо перейти в раздел Resolution and Presentation по пути File => Build Settings => Player Settings и выбрать шаблон Uniton Connect.

Теперь возвращаемся к Build Settings, выбираем платформу сборку WebGL (в случае, если она не установлена, то её нужно установить) и жмём кнопку Build.
После успешной сборки, необходимо загрузить её файлы на какой-нибудь статический хостинг. Здесь могут подойди Github Pages, Versel или тот же Itch.io, инструкции по деплою прикрепил.
Тестирование функционала
После успешной инициализации, можно нажать на кнопку коннекта кошелька и увидеть следующее окно.

В нём будет отображаться список кошельков с прямым подключением или по QR-коду. Затем нужно только выбрать конкретный, в котором у вас имеется активный адрес и подключиться желаемым способом.

После успешного подключения, в текстовом поле, отобразиться сокращённый адрес вашего кошелька. Конкретно на данном скриншоте представлен укороченный формат Non Bounceable адреса, а у TON блокчейна их всего 3 (об их отличиях можно ознакомиться тут):
Raw/Hex,
Non Bounceable,
Bounceable
Соответственно, при нажатие на кнопку для отключения кошелька, будет произведена чистка локального хранилища подключений. Без дополнительных модальных окон, как в 1 случае.
Отправка TON транзакций
Для проведения транзакции, необходимо иметь на балансе кошелька от 0.01 TON, так как газ нужно чем-то оплачивать :D
P.S: у кошельков может отличаться минимальная сумма для отправки и дополнительные комиссионные сборы, имейте это в виду.
Теперь необходимо добавить ещё одну кнопку в наш канвас, которая будет отвечать за логику отправки тонкоина. Ну и создадим ещё один скрипт, в котором пропишем следующий код:
public sealed class TonTransactionSendingExample: MonoBehaviour
{
[SerializeField, Space] private Button _sendTransctionButton;
private UnitonConnectSDK _unitonConnect;
private string _latestTransactionHash;
private void OnDisable()
{
_unitonConnect.OnTonTransactionSended -= TonTransactionSendingFinished;
_unitonConnect.OnTonTransactionSendFailed -= TonTransactionSendFailed;
_unitonConnect.OnTonTransactionConfirmed -= TonTransactionConfirmed;
_sendTransctionButton.onClick.RemoveListener(Send);
}
private void Start()
{
_unitonConnect = UnitonConnectSDK.Instance;
_unitonConnect.OnTonTransactionSended += TonTransactionSendingFinished;
_unitonConnect.OnTonTransactionSendFailed += TonTransactionSendFailed;
_unitonConnect.OnTonTransactionConfirmed += TonTransactionConfirmed;
_sendTransctionButton.onClick.AddListener(Send);
}
private void Send()
{
if (!_unitonConnect.IsWalletConnected)
{
return;
}
var recipientAddress = "EQDPwEk-cnQXEfFaaNVXywpbKACUMwVRupkgWjhr_f4UrpH_";
var message = "Hello Ton!";
_unitonConnect.SendTransaction(recipientAddress, (decimal)10.0f, message);
// Без сообщения
// _unitonConnect.SendTransaction(recipientAddress, (decimal)10.0f);
}
private void TransactionSendingFinished(string transactionHash)
{
_latestTransactionHash = transactionHash;
Debug.Log($"Ton transaction sended, hash: {transactionHash}");
}
private void TonTransactionSendFailed(string errorMessage)
{
Debug.LogError($"Failed to send ton transaction, reason: {errorMessage}");
}
private void TonTransactionConfirmed(
SuccessTransactionData transactionData)
{
Debug.Log($"Ton transaction {_latestTransactionHash} " +
$"confirmed in blockchain with status: {transactionData.IsSuccess}");
var status = transactionData.IsSuccess;
var newBalance = transactionData.EndBalance.FromNanoton();
var fee = transactionData.TotalFees.FromNanoton();
var sendedAmount = transactionData.OutMessages[0].Value.FromNanoton();
var recipientAddress = transactionData.OutMessages[0].Recipient.Address;
var convertedAddress = WalletConnectUtils.GetNonBounceableAddress(recipientAddress);
var message = transactionData.OutMessages[0].DecodedBody.MessageText;
var transactionDetails = $"Loaded TON transaction data: \n" +
$"STATUS: {transactionData.IsSuccess},\n" +
$"HASH: {_latestTransactionHash},\n" +
$"NEW BALANCE: {newBalance} TON,\n" +
$"TOTAL FEE: {fee} TON,\n" +
$"SENDED AMOUNT: {sendedAmount} TON,\n" +
$"RECIPIENT ADDRESS: {convertedAddress},\n" +
$"MESSAGE: {message}";
Debug.Log(transactionDetails);
}
}
Стоит отметить, что подтверждение факта отправки успешной транзакции доступно в двух видах:
Локальное (через отслеживание события от самого кошелька),
В реальном времени (через подтверждение в блокчейне).
Событие OnTonTransactionSended как раз отвечает за 1 способ валидации статуса и её результат можно получить всего за несколько секунд.
Во втором случае, событие OnTonTransactionConfirmed придёт с задержкой (от 10-15 секунд, но при высокой нагрузке блокчейна, время подтверждения может быть дольше).
P.S: для лучшего пользовательского опыта, стоит отобразить анимацию загрузки, если планируете получить результат второго события.
Ещё на моменте инициализации библиотеки, было упоминание некого манифеста dApp. При активированном тестовом режиме, используются данные демо приложения самой либы. Эту конфигурацию можно найти, перейдя с главного экрана по пути Uniton Connect => dApp Config.

В поле "Project URL" просто укажите домен, где осуществляете деплой веб сборки проекта. На его основе будет добавлен путь к файлу конфига, для его корректного считывания кошельками. Поле "API Server URL" можете оставить как есть или пустым. Оно не нужно в базовом функционале библиотеки и необходимо для DeFi модуля. Ну а поле "Name" отвечает за имя вашего dApp, которое будет отображаться вместо домена, в некоторых кошельках.
P.S: при выборе картинки для конфига, стоит выключить какое-либо сжатие в настройках импорта или выбрать RGBA 32 bit. Это необходимо для её корректного переноса из файлов проекта в директорию сборки.
По итогу, после успешного билда, в директорию будет добавлен json файл с конфигурацией вашего dApp.
Заключение
На этом базовый функционал библиотеки Uniton Connect заканчивается. Можно дополнительно ознакомиться с демо апкой либы, в формате мини приложения или прямо в браузере.
Всё остальное, что связано с жетонами и NFT уже входит в DeFi модуль. Возможно, напишу по этому случаю ещё один гайд, если будет на это запрос.
К слову, у меня есть коммьюнити разработчиков игр, которые пилят проекты под Telegram и TON блокчейн в том числе, так что заинтересованным welcome. Буду рад новым участникам!