В прошлой статье мы дополнили систему риск-менеджмента биржи, а в этой — подключаем кошельки к цепочке Solana. Модель аккаунтов, логирование и механизм подтверждения в Solana существенно отличаются от цепочек на базе Ethereum. Если использовать подходы Ethereum, легко наткнуться на ошибки. Ниже мы разберем общую концепцию работы с Solana.
Понимание особенностей Solana
Модель аккаунтов Solana
Solana использует разделение программ и данных: программы могут быть общими, а данные хранятся в отдельных PDA (Program Derived Address) аккаунтах. Поскольку программы — общие, для различения токенов используют Token Mint. Аккаунт 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
Блоки в Solana создаются примерно за 400 мс. После 32 подтверждений (около 12 секунд) блок считается окончательным (finalized). Если требования к скорости не очень высоки, достаточно доверять только finalized-блокам.
Для более высокой скорости необходимо учитывать возможные реорганизации блоков, хотя они случаются редко. В отличие от Ethereum, в Solana цепочка не строится на основе parentBlockHash, поэтому нельзя определить ветвление по сравнению parentBlockHash и хеша блока.
Для обнаружения реорганизаций нужно хранить в локальной базе данных хеши блоков по слотам. Если для одного слота меняется блокхеш, значит произошел откат.
Понимание особенностей 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 и кошелька, используется при сканировании |
Объяснение полей:
Поддержка пополнений
Для обработки пополнений необходимо постоянно сканировать цепочку. Есть два подхода:
Сканирование подписей (getSignaturesForAddress):
Передается адрес ATA, вызывается с параметрами before, until, limit, чтобы получать новые подписи. Эти адреса — сгенерированные для пользователя ATA или programID. После получения подписей вызывается getTransaction для получения деталей.
Сканирование блоков (getBlock):
Постоянно запрашиваем последние слоты, вызываем getBlock для получения транзакций и анализируем инструкции.
Первый метод подходит при небольшом числе аккаунтов, второй — при большом. В нашем случае используем второй.
Обратите внимание: из-за высокого трафика и TPS в Solana, в реальной среде может возникнуть задержка обработки. Для этого используют очередь сообщений (Kafka, RabbitMQ), чтобы фильтровать и сохранять потенциальные события пополнения. Также для ускорения можно использовать Redis для хранения горячих данных. При большом числе адресов — деление по ATA для параллизации.
Альтернативно — сторонние индексеры (например, RPC-провайдеры с Webhook и расширенными фильтрами), которые позволяют получать события без самостоятельного сканирования.
Процесс сканирования блоков
Используем метод 2 — сканирование блоков. Основные шаги:
Инициализация и загрузка истории (performInitialSync):
Обрабатываем слоты с последнего завершенного, проверяя каждый слот, обновляем целевые параметры. Используем подтверждение confirmed.
Постоянное сканирование новых слотов (scanNewSlots):
Обновляем информацию о новых слотах, проверяем подтверждение и возможные откаты.
Анализ блока (txParser.parseBlock):
Вызываем getBlock для слота, перебираем транзакции, инструкции и метаданные. Обрабатываем только успешные транзакции.
Анализ инструкций (txParser.parseInstruction):
Обработка откатов:
Постоянно сравниваем текущий блокхеш с сохраненным для слота. Если есть изменение — происходит откат.
Пример кода:
// scanSingleSlot.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)) {
// обработка
}
}
// Токен перевод
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)) {
// обработка
}
}
}
}
}
Обработка пополнений осуществляется с учетом безопасности: после проверки данных — запись в таблицу транзакций.
Вывод средств
Процесс вывода схож с EVM, но есть отличия:
Процесс:
Пример кода:
// Создание инструкции перевода SOL
const instruction = getTransferSolInstruction({
source: hotWalletSigner,
destination: solanaAddress,
amount: BigInt(amount)
});
// Создание инструкции перевода токенов
const instruction = getTransferInstruction({
source: sourceAta,
destination: destAta,
authority: hotWalletSigner,
amount: BigInt(amount)
});
// Создание и подпись транзакции
const transactionMessage = createTransactionMessage({
feePayer: hotWalletSigner,
recentBlockhash: await getRecentBlockhash(),
instructions: [instruction]
});
const signedTx = await signTransaction(transactionMessage);
const encodedTx = getBase64EncodedWireTransaction(signedTx);
Отправка осуществляется через @solana/web3.js:
const solanaRpc = chainConfigManager.getSolanaRpc();
const txSignature = await solanaRpc.sendTransaction(encodedTx);
Реализация находится в файлах:
Оптимизации, которые еще нужно реализовать:
Итог
Интеграция Solana в биржу не требует кардинальных изменений архитектуры, главное — адаптировать модель аккаунтов, структуру транзакций и механизм подтверждения.
Для пополнений важно заранее создавать и поддерживать таблицу соответствия ATA и кошелькам, а также отслеживать изменения blockhash для обнаружения реорганизаций.
При выводе — получать актуальный recentBlockhash и учитывать различия в токенах.
Связанные статьи
На этой неделе спотовые ETF на Ethereum в США чистый отток составил 60 миллионов долларов, а спотовые ETF на Solana чистый приток составил 20,40 миллиона долларов
Кит Solana разблокирует $163 миллионов ставки за раз - U.Today
Прогноз цены BTC накаляется, Solana расширяется, а APEMARS появляется среди лучших альткойнов для инвестиций...
GalaChain запускает план расширения экосистемы, GalaSwap поддерживает подключение активов Solana, TON и Ethereum
Председатель Фонда Solana Лили Лю объявила о «смерти блокчейн-игр», общая капитализация упала на 87%
Председатель фонда Solana: блокчейн-игры умерли и не вернутся