Na nossa última publicação, complementámos o sistema de controlo de riscos da bolsa. Nesta, vamos abordar a integração da carteira da bolsa com a cadeia Solana. O modelo de contas, armazenamento de logs e mecanismo de confirmação do Solana diferem bastante das cadeias baseadas em Ethereum. Se utilizarmos a abordagem do Ethereum, é fácil cometer erros. A seguir, faremos uma análise geral do raciocínio para lidar com o Solana.
Compreender o Solana de forma única
Modelo de contas do Solana
O Solana utiliza um modelo de separação entre programas e dados, onde os programas podem ser reutilizados, enquanto os dados do programa são armazenados em contas PDA (Program Derived Address) específicas. Como os programas são comuns, é necessário um Token Mint para distinguir diferentes tokens. A conta Token Mint armazena metadados globais do token, como autoridade de emissão (mint_authority), suprimento total (supply), número de casas decimais (decimals), etc.
Cada token possui um endereço de conta Mint único, por exemplo, o USD Coin (USDC) na rede principal do Solana tem o endereço de Mint EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.
No Solana, existem duas versões de programas SPL Token: uma é SPL Token e outra é SPL Token-2022. Cada SPL Token tem uma ATA (Associated Token Account) independente que armazena o saldo do utilizador. Quando ocorre uma transferência de token, na verdade, chama-se o programa correspondente para transferir entre contas ATA.
Limitações do Log do Solana
No Ethereum, obtém-se as transferências de tokens analisando os logs históricos. No entanto, os logs do Solana não são preservados permanentemente por padrão, e não pertencem ao estado do livro-razão (não há um filtro Bloom para logs). Além disso, podem ser truncados durante a execução.
Por isso, não podemos simplesmente escanear logs para reconciliar depósitos, mas sim usar funções como getBlock ou getSignaturesForAddress para interpretar as instruções.
Confirmação e reorganização do Solana
O tempo de bloco do Solana é de aproximadamente 400ms. Após 32 confirmações (cerca de 12 segundos), o bloco atinge o estado finalizado (finalized). Se a exigência de tempo real não for alta, uma abordagem simples é confiar apenas nos blocos finalizados.
Para maior reatividade, é necessário considerar possíveis reorganizações de blocos, embora sejam raras. O consenso do Solana não depende do parentBlockHash para formar a cadeia, ao contrário do Ethereum, que usa parentBlockHash e blockHash para detectar forks. Como determinar se um bloco foi reorganizado?
Ao escanear localmente, devemos registrar o hash do bloco de cada slot. Se o hash de um slot específico mudar, indica uma reversão.
Compreendendo as diferenças do Solana, podemos avançar para a implementação, começando pelas modificações na base de dados:
Design da base de dados
Como o Solana possui dois tipos de tokens, devemos acrescentar uma coluna token_type na tabela tokens para distinguir entre spl-token e spl-token-2022.
Embora os endereços do Solana sejam diferentes dos do Ethereum, podem ser derivados usando BIP32 e BIP44, apenas com caminhos de derivação diferentes. Assim, podemos manter a tabela wallets existente, mas para suportar o mapeamento ATA e rastreamento de blocos do Solana, é necessário criar as seguintes tabelas:
| Nome da Tabela | Campos-Chave | Descrição |
|---|---|---|
| solana_slots | slot, block_hash, status, parent_slot | Armazena informações redundantes de slots, útil para detectar forks e acionar rollback |
| solana_transactions | tx_hash, slot, to_addr, token_mint, amount, type | Detalhes de depósitos/saques, tx_hash único para rastreamento de assinaturas duplas |
| solana_token_accounts | wallet_id, wallet_address, token_mint, ata_address | Regista o mapeamento ATA do utilizador, o módulo de scan pode consultar por ata_address |
Detalhes adicionais:
Para detalhes de definição, consulte db_gateway/database.md.
Processamento de depósitos de utilizador
Para processar depósitos, é necessário escanear continuamente os dados na cadeia do Solana, usando principalmente duas abordagens:
Método 1:
Escanear assinaturas de um endereço, chamando getSignaturesForAddress com o endereço do ATA gerado para o utilizador ou o programID (atenção: transferências do spl-token não incluem o endereço de mint na instrução). Passando os parâmetros before, until e limit, podemos obter assinaturas incrementais. Depois, usamos getTransaction para obter detalhes das transações.
Este método é adequado para poucos utilizadores ou contas. Para um volume elevado, o método de escanear blocos é preferível, que é o que utilizamos aqui.
Método 2:
Escanear blocos, obtendo o slot mais recente, chamando getBlock para obter detalhes completos, assinaturas e contas, filtrando por instruções e contas relevantes.
Nota: devido ao alto volume de transações e TPS do Solana, em produção, a velocidade de análise pode ficar aquém do ritmo de blocos. Recomenda-se usar filas de mensagens (Kafka, RabbitMQ) para filtrar transferências de tokens e enviar eventos potenciais de depósito. Utilizar Redis para armazenar dados de hotspots pode acelerar a filtragem. Para muitas addresses, dividir por ATA e usar múltiplos consumidores aumenta a eficiência.
Se não desejar escanear blocos manualmente, pode usar serviços de indexadores de terceiros, que oferecem Webhook, monitorização de contas e filtragem avançada, suportando grandes volumes de dados.
Fluxo de escaneamento de blocos
Utilizamos o método 2, com código principal em scan/solana-scan, nos ficheiros blockScanner.ts e txParser.ts. O fluxo geral:
1. Sincronização inicial (performInitialSync):
2. Escaneamento contínuo (scanNewSlots):
3. Análise do bloco (txParser.parseBlock):
4. Análise de instruções (txParser.parseInstruction):
Ao detectar uma transação de depósito, após validação de segurança com DB Gateway e assinatura de risco, os dados são gravados na tabela de fluxos de fundos (credits).
Retiradas
O processo de retirada no Solana é semelhante ao do EVM, mas com diferenças na construção da transação:
Fluxo de retirada
[Imagem ilustrativa]
A obtenção do recentBlockhash deve ocorrer após a verificação de risco, para garantir que a transação seja válida.
Código principal de assinatura:
Envio da transação à rede
Usa-se @solana/web3.js:
const solanaRpc = chainConfigManager.getSolanaRpc();
const txSignature = await solanaRpc.sendTransaction(signedTransaction, ...);
Os detalhes completos do código de retirada encontram-se em:
Duas melhorias pendentes:
Resumo
A integração do Solana na bolsa mantém a arquitetura geral, mas requer adaptação ao seu modelo de contas, estrutura de transações e mecanismo de consenso.
No processamento de depósitos, criar e manter o mapeamento ATA → carteira, monitorar mudanças de blockhash para detectar reorganizações, e atualizar o estado da transação de confirmed para finalized.
Na retirada, obter o recentBlockhash mais recente, distinguir entre SPL Token e Token-2022, e construir transações específicas para cada caso.
Related Articles
SOL Consolida-se perto de $84 enquanto o gráfico destaca possível zona de procura $45
O protocolo DeFi do ecossistema Solana Drift lançará a funcionalidade de recarga multi-chain em 12 de março