Перевірка балансу SOL — перша операція, з якої починається будь-яка взаємодія з блокчейном Solana через код. Нижче наведено повний цикл: від одиночного запиту до RPC (Remote Procedure Call) до відображення відформатованого значення в інтерфейсі користувача.

Середовище: Node.js 18+, TypeScript 5.x, @solana/web3.js 1.95.x.
Кластер: Devnet.
Передумови: встановлений пакет @solana/web3.js, наявність публічного ключа гаманця у форматі PublicKey.

Запит балансу

connection.getBalance(publicKey); Форматування lamports у SOL

Solana зберігає баланс у найменшій одиниці — lamports. Один SOL дорівнює 1 000 000 000 lamports. SDK повертає саме кількість lamports, тому перетворення лежить повністю на вашому коді.

Базовий запит виглядає так:

const balance = await connection.getBalance(publicKey);

Метод getBalance приймає два аргументи: об'єкт PublicKey та необов'язковий об'єкт GetBalanceConfig, де можна вказати commitment (за замовчуванням — "finalized").

Повний приклад для Devnet:

import { Connection, PublicKey } from "@solana/web3.js";
import { LAMPORTS_PER_SOL } from "@solana/web3.js";

const connection = new Connection("https://api.devnet.solana.com", "confirmed");
const publicKey = new PublicKey(" Ваш_публічний_ключ_гаманця ");

const lamports = await connection.getBalance(publicKey);
const sol = lamports / LAMPORTS_PER_SOL;

console.log(`Баланс: ${sol} SOL`);

Очікуваний результат: консоль виведе число з десятковими знаками, наприклад 1.5 SOL. Якщо гаманець порожній — 0 SOL.

Важливо: константа LAMPORTS_PER_SOL експортується з @solana/web3.js і дорівнює 1_000_000_000. Використовуйте її замість хардкоду, щоб уникнути помилок при копіюванні.

Баланс у різних контекстах

Баланс гаманця користувача

Гаманець користувача — це звичайний акаунт, керований парою ключів. Баланс такого акаунта показує суму SOL, доступну для витрат (за вирахуванням комісій за транзакції). Запит здійснюється так само, як у попередньому розділі.

Баланс програмного акаунта (rent-exempt)

Програмні акаунти (Program Derived Accounts, PDA) зберігають дані й повинні мати мінімальний баланс, щоб не бути видаленими збірщиком сміття. Цей мінімум називається rent-exempt мінімумом.

Щоб дізнатися, скільки SOL заблоковано під дані акаунта:

const balance = await connection.getBalance(pda);
const rentExemptMinimum = await connection.getMinimumBalanceForRentExemption(dataSize);

Якщо balance дорівнює rentExemptMinimum — акаунт містить лише мінімально необхідну суму для зберігання даних. Якщо більше — різниця доступна для використання в межах програмної логіки (наприклад, як escrow).

Примітка: у концептуальних прикладах можна порівнювати ці значення безпосередньо. У production-рішеннях обов'язково перевіряйте актуальний розмір даних акаунта через connection.getAccountInfo, оскільки розмір може змінюватися залежно від версії програми.

Періодичне оновлення

Інтервал запитів до RPC

Баланс акаунта змінюється лише коли надходить або відправляється транзакція. Тому опитувати RPC кожну секунду — марнотратство. Для Devnet достатньо інтервалу 10–15 секунд. Для production-застосунків, що працюють з Mainnet-Beta, рекомендований інтервал — 15–30 секунд, залежно від критичності даних.

Оптимізація: кешування та підписки

Замість поллінгу (повторних запитів за таймером) Solana пропонує механізм підписок через WebSocket:

connection.onAccountChange(publicKey, (updatedAccountInfo) => {
  const newBalance = updatedAccountInfo.lamports;
  console.log("Оновлений баланс:", newBalance / LAMPORTS_PER_SOL, "SOL");
});

Цей підхід надсилає оновлення лише тоді, коли стан акаунта реально змінюється. Це значно зменшує навантаження на RPC-вузол і мережу.

Концептуальний приклад: підписка з console.log підходить для локальної перевірки.
Production-рішення: обгорніть підписку в клас із методами subscribe та unsubscribe, додайте обробку розриву з'єднання з повторним підключенням (reconnect) і ліміт на кількість спроб.

Відображення у UI

Форматування числа з комами

Число 1.543210000 у інтерфейсі виглядає неохайно. Використовуйте форматування з фіксованою кількістю знаків і роздільниками розрядів:

function formatSol(lamports: number): string {
  const sol = lamports / LAMPORTS_PER_SOL;
  return sol.toLocaleString("uk-UA", {
    minimumFractionDigits: 2,
    maximumFractionDigits: 4,
  });
}

Результат: 1,5432 замість 1.543210000. Локаль "uk-UA" автоматично підставить кому як десятковий роздільник і пробіл як роздільник тисяч.

Відображення еквіваленту в гривнях (курс)

Для показу фіатного еквівалента потрібен зовнішній джерело курсу. У концептуальному прикладі можна використати хардкожене значення для перевірки логіки:

const SOL_UAH_RATE = 1500; // Приклад для перевірки формул
const uahEquivalent = sol * SOL_UAH_RATE;
console.log(`≈ ${uahEquivalent.toLocaleString("uk-UA")} грн`);

Для production: курс SOL/UAH змінюється кожну хвилину. Отримуйте його з агрегатора курсів (CoinGecko, Birdeye тощо) перед обчисленням. Не кешуйте курс довше ніж на 60 секунд. Обов'язково покажіть користувачу час останнього оновлення курсу, щоб уникнути плутанини.

Типові помилки

Невірне перетворення lamports → SOL

Найчастіша помилка — множення замість ділення або використання хибного коефіцієнта:

  • Помилка: lamports * LAMPORTS_PER_SOL — дає абсурдно велике число.
  • Помилка: lamports / 1_000_000 — використано коефіцієнт для MICROSOL (неіснуюча одиниця, плутанина з іншими блокчейнами).
  • Правильно: lamports / LAMPORTS_PER_SOL — де LAMPORTS_PER_SOL = 1_000_000_000.

Перевірка: якщо гаманець містить 1 SOL, getBalance поверне 1000000000. Після ділення має вийти рівно 1.

Занадто часті запити до RPC

Публічні RPC-вузли Devnet мають ліміти на кількість запитів. Якщо ваш застосунок робить getBalance кожні 100 мс для десятків акаунтів одночасно, ви швидко отримаєте помилку 429 (Too Many Requests).

Як уникнути:

  • Використовуйте onAccountChange замість поллінгу там, де це можливо.
  • Для кількох акаунтів застосовуйте getMultipleBalances — один запит повертає масив балансів:

const balances = await connection.getMultipleBalances([pubkey1, pubkey2, pubkey3]);

  • Додайте локальне кешування: якщо з останнього запиту минуло менше ніж N секунд, повертайте кешоване значення.
  • Для production використовуйте власний RPC-вузол або платний план у провайдера (Helius, QuickNode, Triton тощо).

Наступний крок: після того, як ви впевнено працюєте з балансами на Devnet, варто налаштувати локальне середовище. Перейдіть до розділу Як запустити локальний validator для розробки, щоб не залежати від доступності публічних RPC-вузлів.

Джерела