В прошлой статье мы дополнили систему риск-менеджмента биржи, а в этой — подключаем кошельки к цепочке 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 — уникальный для отслеживания
Отслеживание связки ATA и кошелька, используется при сканировании
Объяснение полей:
solana_slots: хранит статус подтверждения (confirmed, finalized, skipped).
solana_transactions: хранит суммы в минимальных единицах (лампорт), тип операции (deposit/withdraw).
solana_token_accounts: связывает 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):
SOL переводы: по системной программе, проверяем destination.
Токен переводы: по программам SPL Token и SPL Token-2022, ищем transfer или transferChecked, сопоставляем ATA с кошельком через базу данных.
Обработка откатов:
Постоянно сравниваем текущий блокхеш с сохраненным для слота. Если есть изменение — происходит откат.
Пример кода:
// 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, но есть отличия:
В Solana два типа токенов: SPL Token и SPL Token 2022, их programId различаются. При формировании транзакции нужно учитывать это.
Транзакция состоит из message и signatures. В качестве nonce используется recentBlockhash, который нужно получать в реальном времени.
Процесс:
Формируем инструкции для перевода SOL или токенов.
Проверка существования ATA перед выводом (создавать при необходимости).
Установка computeUnitPrice для повышения приоритета при перегруженности сети.
Итог
Интеграция Solana в биржу не требует кардинальных изменений архитектуры, главное — адаптировать модель аккаунтов, структуру транзакций и механизм подтверждения.
Для пополнений важно заранее создавать и поддерживать таблицу соответствия ATA и кошелькам, а также отслеживать изменения blockhash для обнаружения реорганизаций.
При выводе — получать актуальный recentBlockhash и учитывать различия в токенах.
На этой странице может содержаться сторонний контент, который предоставляется исключительно в информационных целях (не в качестве заявлений/гарантий) и не должен рассматриваться как поддержка взглядов компании Gate или как финансовый или профессиональный совет. Подробности смотрите в разделе «Отказ от ответственности» .
Разработка системы кошелька для биржи — интеграция цепочки Solana
В прошлой статье мы дополнили систему риск-менеджмента биржи, а в этой — подключаем кошельки к цепочке 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 и отслеживания блоков добавляем три таблицы:
Объяснение полей:
Поддержка пополнений
Для обработки пополнений необходимо постоянно сканировать цепочку. Есть два подхода:
Сканирование подписей (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):
Обработка откатов:
Постоянно сравниваем текущий блокхеш с сохраненным для слота. Если есть изменение — происходит откат.
Пример кода:
Обработка пополнений осуществляется с учетом безопасности: после проверки данных — запись в таблицу транзакций.
Вывод средств
Процесс вывода схож с EVM, но есть отличия:
Процесс:
Пример кода:
Отправка осуществляется через @solana/web3.js:
Реализация находится в файлах:
Оптимизации, которые еще нужно реализовать:
Итог
Интеграция Solana в биржу не требует кардинальных изменений архитектуры, главное — адаптировать модель аккаунтов, структуру транзакций и механизм подтверждения.
Для пополнений важно заранее создавать и поддерживать таблицу соответствия ATA и кошелькам, а также отслеживать изменения blockhash для обнаружения реорганизаций.
При выводе — получать актуальный recentBlockhash и учитывать различия в токенах.