Усі статті
6 хв читання

Як дізнатися баланс USDT на гаманці TON одним викликом

Як отримати баланс USDT на гаманці TON одним викликом get_jetton_balance — джетон-гаманець обчислюється он-чейн, індексер не потрібен.

баланс USDT TONget_jetton_balanceджетони TONMCP для TONTONNodedecimals джетона

Гаманець агента відкритий, get_balance повернув чесні кілька GRAM — а USDT нуль. Хоча ви точно знаєте, що стейблкоїни на цю адресу приходили. Знайомо? Гаманець виглядає порожнім, хоча на ньому лежить 500 USDT. Це не баг і не зниклі гроші — ви просто спитали не в того контракту. І саме тут падає більшість перших інтеграцій ШІ-агента з TON: агент читає не ту адресу.

Чому баланс USDT — це не баланс TON-гаманця

В Ethereum ви звикли, що токен ERC-20 «лежить на адресі»: контракт токена зберігає табличку address → balance, і щоб дізнатися баланс, ви звертаєтеся до цього єдиного контракту. У TON модель інша, і це перше джерело плутанини.

Нативна монета GRAM (колишній Toncoin; мережа, як і раніше, називається TON) лежить безпосередньо на смарт-контракті вашого гаманця — її читає get_balance одним зверненням до стану акаунта. А USDT — це джетон (jetton, стандарт TON для взаємозамінних токенів). І баланс джетона зберігається не на вашому основному гаманці, а на окремому маленькому контракті — джетон-гаманці (jetton wallet).

Аналогія: ваш основний TON-гаманець — це ви як людина. А джетон-гаманець USDT — це окремий рахунок на ваше ім’я, відкритий конкретним банком (майстер-контрактом USDT). Питати «скільки в мене доларів» у самої людини безглуздо — гроші на рахунку, а не в кишені. У кожної пари «власник + джетон» — свій джетон-гаманець: для USDT одна адреса, для NOT інша, для будь-якого джетона третя.

Добра новина: адреса цього джетон-гаманця не випадкова. Вона детерміновано виводиться з двох речей:

  • адреси власника (ваш звичайний TON-гаманець, EQ…/UQ…);
  • адреси майстер-контракту джетона (jetton master — для USDT це один фіксований контракт).

Погана новина: щоб чесно обчислити цю адресу, треба звернутися до майстер-контракту, викликати його get-метод, а потім прочитати стан джетон-гаманця. Вручну це кілька кроків, і саме на них спотикаються інтеграції.

get_jetton_balance: один виклик замість індексера

Зазвичай цю задачу розв’язують одним із двох способів, і обидва незручні:

  • Власний індексер. Підняти ноду, проіндексувати джетон-перекази в базу, підтримувати її в актуальному стані. Дорого й ненадійно заради одного числа, а дані завжди трохи відстають від чейна.
  • Публічний HTTP-API. Швидко впирається в ліміти: без ключа це близько одного запиту на секунду, а в разі перевищення ви отримуєте чесний HTTP 429 Too Many Requests. Плюс ви залежите від чужої індексації та її глибини.

Інструмент get_jetton_balance із TONNode прибирає обидві проблеми. Ви передаєте йому:

  • адресу власника — звичайний TON-гаманець користувача (EQ…/UQ…);
  • ідентифікатор джетона — наприклад, USDT.

Далі сервер сам робить усю роботу он-чейн:

  1. викликає get-метод майстер-контракту джетона, який за адресою власника повертає адресу його джетон-гаманця (те саме детерміноване виведення);
  2. читає баланс із цього джетон-гаманця і повертає його вам.

Жодного стороннього індексера, жодної бази, жодної розсинхронізації — лише пряме читання стану мережі через get-методи контрактів.

TONNode — це hosted MCP-сервер для TON. MCP (Model Context Protocol) — стандарт, за яким ШІ-агенти (Claude, Cursor, ChatGPT/Codex і будь-який MCP-клієнт) викликають зовнішні інструменти. Тобто get_jetton_balance — це не рядок у вашому коді, а інструмент, який агент смикає сам, коли користувач питає про баланс. Під капотом пакет @tonnode/mcp (open source, MIT) працює за нативним ADNL-протоколом TON, без проміжних HTTP-прошарків — агент спілкується з мережею напряму, а не через черговий REST-шлюз.

Приклад: промпт агенту і що повертається

Підключення локальне, без ключа і без картки. Додайте в конфіг MCP-клієнта (Claude Desktop, Cursor, будь-який MCP-сумісний):

{
  "mcpServers": {
    "ton": {
      "command": "npx",
      "args": ["-y", "@tonnode/mcp"]
    }
  }
}

Після цього агенту досить звичайного промпта природною мовою:

Скільки USDT на гаманці UQAbc…xyz? Поверни людиночитане значення.

Агент сам вибере інструмент get_jetton_balance, передасть адресу власника і джетон USDT, а сервер поверне баланс — але не у звичних «доларах», а в raw-одиницях (мінімальних неподільних одиницях джетона). Крім самого балансу, у відповіді приходить і адреса джетон-гаманця, яку сервер обчислив он-чейн, — корисно, якщо далі ви хочете відстежувати перекази саме цього контракту. Сам баланс у нашому прикладі — значення на кшталт 12500000.

Але 12500000 — це не 12.5 мільйона USDT. Тут починається друга пастка, на якій легко помилитися.

Raw-одиниці та decimals: чому в USDT 6, а не 9

Блокчейни не працюють із дробами. Усі суми зберігаються в цілочисельних raw-одиницях, а «людське» значення виходить діленням на 10^decimals, де decimals — властивість конкретного джетона. Це як копійки та гривні: на низькому рівні все в копійках, а decimals каже, де поставити кому.

Ключовий нюанс TON: у різних джетонів різна кількість decimals.

  • У нативного GRAM і в більшості джетонів TON decimals = 9.
  • А в USDT на TON decimals = 6.

Тому те саме raw-значення означає геть різні суми. Перераховуємо наш приклад правильно:

raw      = 12500000
decimals = 6            // саме для USDT
human = 12500000 / 10^6 = 12500000 / 1_000_000 = 12.5 USDT

12.5 USDT, а не 12.5 мільйона. Якби ви за інерцією поділили на 10^9 (як для звичайного джетона), отримали б 0.0125 — помилка в тисячу разів. Те саме число — три порядки різниці. Саме так губляться гроші в наївних інтеграціях: жорстко зашитий дільник 10^9 для всього підряд. Тому ніколи не хардкодьте decimals — беріть їх із метаданих самого джетона.

get_jetton_info: звідки взяти decimals і метадані джетона

Щоб не вгадувати, є парний інструмент — get_jetton_info. Він читає майстер-контракт джетона і віддає його метадані:

  • ім’я (name);
  • символ (symbol);
  • decimals — те саме число, за яким рахується дільник;
  • емісію (total supply).

Надійний сценарій для агента — два виклики: якщо джетон незнайомий, спершу get_jetton_info, щоб дізнатися decimals, потім get_jetton_balance, щоб узяти raw-баланс, і лише потім ділення raw / 10^decimals для відображення.

1) get_jetton_info(USDT)            -> decimals = 6
2) get_jetton_balance(owner, USDT)  -> raw = 12500000
3) human = 12500000 / 10^6          -> 12.5 USDT

Промпт можна сформулювати так, щоб агент сам склеїв ці кроки:

Візьми decimals для USDT через get_jetton_info, потім баланс гаманця UQAbc…xyz через get_jetton_balance і переведи raw у людиночитане число.

Такий порядок обов’язковий, якщо ви працюєте з довільними джетонами, а не лише з USDT: для незнайомого токена ви заздалегідь не знаєте, 6 у нього decimals чи 9. Для USDT decimals = 6 — константа, але звичка тягнути її з get_jetton_info врятує вас на першому ж нестандартному джетоні. Той самий прийом лежить в основі детекту вхідних платежів USDT на TON — там decimals критичні, щоб не сплутати 1 USDT із мікроскопічним пилом.

parse_address: офлайн-перевірка адреси перед запитом

Ще одна часта причина «нульового» балансу — крива адреса власника. Користувачі надсилають адреси в різних форматах: EQ… (bounceable), UQ… (non-bounceable), raw (0:…). Перш ніж питати баланс, адресу корисно нормалізувати через parse_address — він офлайн (без звернення до мережі) бере адресу в будь-якому з форматів, конвертує її в усі три (EQ/UQ/raw) і каже, чи коректна вона взагалі.

Це дешево, миттєво і прибирає цілий клас помилок «баланс 0, бо адреса не та» — особливо якщо адреса прийшла з ненадійного джерела, користувацького введення або чату.

Як підключити: безкоштовно локально або hosted

Три інструменти — parse_address, get_jetton_info, get_jetton_balance — дають повну, чесну відповідь на питання «скільки USDT на гаманці» без жодного стороннього індексера.

Безкоштовно локально

Пакет @tonnode/mcpopen source (MIT), лежить на npm і GitHub. Той самий публічний конфіг із прикладу вище (npx -y @tonnode/mcp) дає повний набір інструментів читання, включно з get_jetton_balance, get_jetton_info і parse_address — окремий ключ не потрібен.

Перезапускаєте клієнт — і агент уже читає баланси джетонів через ADNL. Навіщо агенту взагалі окремий MCP-сервер, а не публічний шлюз із лімітами, розбирали в нотатці про MCP для ШІ-агентів на TON. А де закінчується безкоштовний публічний конфіг і чому — у розборі лімітів публічних лайтсерверів TON.

Hosted — коли потрібна пропускна здатність

Коли локального рейту вже мало (боти, бекенди, продакшн-навантаження), перемикаєтеся на hosted-ендпоїнт зі своїм ключем. Набір інструментів скрізь однаковий — усі 16, включно з блоком читання; тарифи відрізняються лише гарантованою пропускною здатністю:

  • Hobby — безкоштовно назавжди, 60 запитів/хв;
  • Pro — $29/міс, 300 запитів/хв;
  • Scale — $199/міс, 1200 запитів/хв.

Hosted-підключення відрізняється лише тим, що ви звертаєтеся до спільного ендпоїнта зі своїм ключем:

{
  "mcpServers": {
    "ton": {
      "type": "http",
      "url": "https://mcp.tonnode.io/mcp",
      "headers": { "Authorization": "Bearer tn_live_…" }
    }
  }
}

Якщо робите дашборд, бота для перевірки балансів або агента, який часто опитує адреси, — беріть ключ, щоб не впиратися в ліміти публічних API і не ловити 429 у найневдаліший момент.

Коротко

  • USDT на TON — джетон, і баланс лежить на окремому джетон-гаманці, а не на основній адресі.
  • get_jetton_balance сам обчислює адресу джетон-гаманця он-чейн і читає баланс — індексер і власна база не потрібні.
  • Баланс приходить у raw-одиницях; для відображення діліть на 10^decimals.
  • У USDT decimals = 6 (дільник 1_000_000), у більшості джетонів — 9. Не хардкодьте — беріть із get_jetton_info.
  • Перевірити весь шлях можна безкоштовно: npx -y @tonnode/mcp, публічний конфіг, повний набір читання.

Безкоштовний ключ Hobby — 60 запитів/хв, без картки — видається одразу після входу: отримати ключ. Його вистачає, щоб прогнати parse_address → get_jetton_info → get_jetton_balance на реальному гаманці й переконатися, що 12500000 raw перетворюються рівно на 12.5 USDT — а не на 12.5 мільйона і не на 0.0125.

Дайте вашому агенту доступ до TON

16 MCP-інструментів: читання, некастодіальні свопи, кросчейн і гаманці. Безкоштовний тариф — 60 зап/хв, картка не потрібна.