Попередній раз ми доповнили систему управління ризиками біржі, а в цій статті розглянемо підключення гаманців до мережі Solana. Модель облікових записів, збереження логів та механізм підтвердження в Solana значно відрізняються від Ethereum-ланцюгів. Якщо використовувати підхід, характерний для Ethereum, можна легко наткнутися на помилки. Нижче наведено загальний огляд підходу до роботи з Solana.
Знайомство з унікальними особливостями Solana
Модель облікових записів Solana
Solana використовує модель, де програми та дані розділені: програми є спільними, а дані зберігаються окремо у PDA (Program Derived Address) облікових записах. Оскільки програми спільні, для розрізнення різних токенів застосовують Token Mint — глобальні метадані токена, що зберігають інформацію, таку як mint authority (право на емісію), загальний обсяг (supply), кількість десяткових знаків (decimals) тощо.
Кожен токен має унікальну адресу Mint, наприклад, USDC у мережі Solana має адресу EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.
В мережі Solana існує дві системи програм для токенів: SPL Token та SPL Token-2022. Для зберігання балансу користувача кожен токен використовує ATA (Associated Token Account). При переказі токенів викликаються відповідні програми для переміщення активів між ATA.
Обмеження логів у Solana
На відміну від Ethereum, де історичні логи транзакцій використовуються для визначення переказів токенів, у Solana логи виконання за замовчуванням не зберігаються довго. Логи не є частиною стану блокчейну і не мають Bloom-фільтрів, а їх вивід може бути обрізаний під час виконання.
Тому для відновлення інформації про депозити/зняття потрібно використовувати getBlock або getSignaturesForAddress для аналізу інструкцій.
Підтвердження та реорганізація блоків у Solana
Час створення блоку — приблизно 400 мс. Після 32 підтверджень (близько 12 секунд) блок вважається finalised. Якщо вимоги до швидкості не дуже високі, можна довіряти лише finalised-блокам.
Для більш високої швидкості потрібно враховувати можливі реорганізації блоків, хоча вони трапляються рідко. Оскільки консенсус Solana не базується на parentBlockHash для формування ланцюга, його не можна використовувати для визначення фрікцій через різницю між parentBlockHash та blockHash, як у Ethereum.
Як визначити реорганізацію?
На локальному рівні слід зберігати blockhash для кожного slot. Якщо для одного slot з’являється різний blockhash — це сигнал про відкат.
Розуміння особливостей Solana дозволяє перейти до реалізації. Спершу розглянемо зміни у базі даних:
Модель бази даних
Оскільки у Solana існує два типи токенів, у таблиці tokens потрібно додати поле token_type для розрізнення SPL Token та SPL Token-2022.
Адреси Solana, хоча й відрізняються від Ethereum, можна отримати шляхом деривації за BIP32/BIP44, але з іншими шляхами. Тому достатньо використовувати існуючу таблицю wallets, доповнивши її для підтримки ATA та слідкування за блоками:
| Назва таблиці | Ключові поля | Опис |
|---|---|---|
| solana_slots | slot, block_hash, status, parent_slot | Зберігає інформацію про слоти для виявлення фрікцій і відкатів |
| solana_transactions | tx_hash, slot, to_addr, token_mint, amount, type | Деталі транзакцій, включаючи депозити та зняття, з унікальним tx_hash для відслідковування |
| solana_token_accounts | wallet_id, wallet_address, token_mint, ata_address | Мапінг ATA до гаманця, що дозволяє швидко знаходити внутрішні облікові записи |
Детальніше про структуру таблиць можна знайти у db_gateway/database.md.
Обробка депозитів користувачів
Для обробки депозитів потрібно постійно сканувати мережу Solana. Є два підходи:
Перший метод: отримання підписів для ATA або programID, що належать користувачу, з використанням getSignaturesForAddress. Потім за допомогою getTransaction отримати деталі транзакцій. Цей спосіб підходить при невеликій кількості облікових записів.
Другий метод: постійне отримання останнього slot і виклик getBlock для аналізу всіх транзакцій у ньому. Це більш ефективно при великій кількості облікових записів.
Примітка: через високий TPS у Solana, у виробничому середовищі може виникнути затримка у обробці логів. Тому рекомендується використовувати черги (Kafka/RabbitMQ) для фільтрації потенційних депозитів і збереження популярних даних у Redis для швидкого доступу.
Альтернативно, можна використовувати сторонні індексатори або RPC-сервіси, що пропонують Webhook або підписки на облікові записи.
Процес сканування
Ми використовуємо метод 2 (сканування за блоками). Основний код реалізовано у модулях scan/solana-scan/blockScanner.ts та txParser.ts. Основні етапи:
Початкове синхронізування (performInitialSync):
Постійне сканування (scanNewSlots):
Аналіз блоку (txParser.parseBlock):
Аналіз інструкцій (txParser.parseInstruction):
Обробка відкатів:
Постійно отримуємо найновий finalizedSlot. Якщо slot ≤ finalizedSlot, він вважається підтвердженим. Для confirmed-слотів перевіряємо, чи не змінився blockhash — це сигнал про відкат.
Приклад основного коду:
// blockScanner.ts - сканування одного слоту
async function scanSingleSlot(slot: number) {
const block = await solanaClient.getBlock(slot);
if (!block) {
await insertSlot({ slot, status: 'skipped' });
return;
}
const finalizedSlot = await getCachedFinalizedSlot();
const status = slot <= finalizedSlot ? 'finalized' : 'confirmed';
await processBlock(slot, block, status);
}
// txParser.ts - парсинг транзакцій
for (const tx of block.transactions) {
if (tx.meta?.err) continue; // пропускаємо неуспішні
const instructions = [
...tx.transaction.message.instructions,
...(tx.meta.innerInstructions ?? []).flatMap(i => i.instructions)
];
for (const ix of instructions) {
// SOL переказ
if (ix.programId === SYSTEM_PROGRAM_ID && ix.parsed?.type === 'transfer') {
if (monitoredAddresses.has(ix.parsed.info.destination)) {
// обробка депозиту
}
}
// Token переказ
if (ix.programId === TOKEN_PROGRAM_ID || ix.programId === TOKEN_2022_PROGRAM_ID) {
if (ix.parsed?.type === 'transfer' || ix.parsed?.type === 'transferChecked') {
const ataAddress = ix.parsed.info.destination;
const walletAddress = ataToWalletMap.get(ataAddress);
if (walletAddress && monitoredAddresses.has(walletAddress)) {
// обробка депозиту
}
}
}
}
}
Після виявлення депозиту, у поєднанні з системою двофакторного контролю (DB Gateway + ризик-менеджмент), дані записуються у таблицю транзакцій.
Зняття
Процес зняття у Solana схожий на Ethereum, але з особливостями:
Процес зняття:
Приклад коду підписання:
// Інструкція для SOL
const instruction = getTransferSolInstruction({
source: hotWalletSigner,
destination: solanaAddress.to,
amount: BigInt(amount)
});
// Інструкція для токенів
const instruction = getTransferInstruction({
source: sourceAta,
destination: destAta,
authority: hotWalletSigner,
amount: BigInt(amount)
});
// Створення повідомлення
const transactionMessage = createTransactionMessage({
feePayer: hotWalletSigner.publicKey,
recentBlockhash: blockhash,
instructions: [instruction]
});
// Підписання
const signedTx = await signTransaction(transactionMessage, [hotWalletSigner]);
// Отримання закодованого для відправки
const signedTransaction = getBase64EncodedWireTransaction(signedTx);
Відправка транзакції:
const solanaRpc = chainConfigManager.getSolanaRpc();
const txSignature = await solanaRpc.sendTransaction(signedTransaction);
Розміщення коду з реалізацією у відповідних модулях:
Додаткові оптимізації:
Підсумки
Інтеграція Solana у біржу вимагає адаптації до її унікальної моделі облікових записів, структури транзакцій та механізмів підтвердження.
Для депозитів важливо підтримувати актуальні мапінги ATA до гаманця, слідкувати за зміною blockhash для виявлення реорганізацій, а також динамічно оновлювати статуси транзакцій.
При зняттях — отримувати актуальний recentBlockhash, формувати транзакції для SOL, SPL Token або Token-2022 відповідно до типу активу.
Пов'язані статті
Фонд Solana запускає Agent Skills, що підтримує AI-агентів та взаємодію з мережею on-chain
Circle знищує 250M USDC у Solana, щомісячний загальний обсяг досягає 10.25B
Топ-4 криптовалюти для купівлі у 2026 році: BlockDAG, Ethereum, Solana та XRP готові до зростання
Solana утримує ключову підтримку, оскільки ралі Bitcoin піднімає крипторинок
ETF на біткойн, ефірі та солані зафіксували змішані чисті припливи 3 квітня