Apresentando saldos históricos de tokens Solana
Autor: Alchemy

Pergunte a uma wallet Solana o que ela possui hoje e qualquer node pode responder em uma chamada. Pergunte o que ela possuía na primavera passada, ou no exato momento antes de ser drenada, e o caminho fácil desaparece. Nodes servem saldos atuais. Eles não mantêm um registro contínuo de quem possuía o quê, e quando. Então a resposta honesta para "o que essa wallet possuía naquela época" sempre foi: reconstrua você mesmo.
Hoje isso muda. getTokenAccountsByOwnerAtSlot retorna tudo o que uma wallet possuía em qualquer ponto passado no tempo, com saldos exatos, em uma única chamada.
O problema de reconstruir o histórico
O getTokenAccountsByOwner padrão só responde uma pergunta: o que essa wallet possui agora. Isso cobre a maioria dos fluxos de apps em produção, mas deixa toda uma classe de perguntas sem resposta.
Para reconstruir um saldo passado você mesmo, é preciso reproduzir toda a vida da conta. Você puxa o histórico completo de assinaturas da wallet com getSignaturesForAddress, busca cada transação com getTransaction, e então re-deriva os saldos slot a slot até o ponto desejado. Para uma wallet ativa isso são milhares de chamadas, muito parsing, e bastante espaço para errar a matemática. Nodes arquivais ajudam a ler estado antigo, mas ainda assim não respondem diretamente "liste as contas de token desse owner no slot X".
Como funciona
O método mantém a sintaxe que você já conhece de getTokenAccountsByOwner e adiciona uma coisa: um slot. Um slot é o relógio da Solana, aproximadamente um bloco, então passar um slot significa "me dê essa wallet como ela estava exatamente naquele ponto da história".
Ao chamar o método, você recebe de volta as contas de token da wallet, os registros individuais que guardam cada token que uma wallet possui. Na Solana uma wallet não guarda saldos diretamente, então listar essas contas é como você lê as posses. Cada uma vem com seu saldo e seus lamports, a pequena quantidade de SOL (frações de uma moeda, 1 SOL equivale a 1 bilhão de lamports) que toda conta carrega para existir on-chain. O método cobre os dois padrões de token da Solana: SPL Token, o original por trás de praticamente todo token conhecido como USDC, e Token-2022, a versão mais nova com extras como taxas de transferência e saldos confidenciais. Esses padrões vivem sob program IDs diferentes, então um único filtro programId retorna apenas contas daquele program.
Por trás da chamada está um índice histórico construído continuamente, um registro versionado de cada conta de token ao longo do tempo: quem possuía qual conta, quanto, e entre quais slots, mantido atualizado conforme novos blocos chegam. Você pode escopar uma query de duas formas. Por mint, para ler o saldo de um único token em um slot passado. Ou por program, para listar toda conta de token possuída sob aquele program naquele slot. Para um portfólio completo cobrindo os dois padrões, chame uma vez com o program ID do SPL Token e uma vez com o program ID do Token-2022, e depois combine os resultados. O exemplo abaixo se restringe apenas ao SPL Token.
const res = await fetch("https://solana-mainnet.g.alchemy.com/v2/{ALCHEMY_API_KEY}", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "getTokenAccountsByOwnerAtSlot",
params: [
"89zoESAF7JqYQz5uhf5eYwg3QsKXQy5QFs4WZQ4hMPnb",
{ programId: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" },
{ encoding: "jsonParsed", slot: 80000000 }
]
})
});
console.log(await res.json());A paginação permanece consistente porque o pageKey fixa o slot que você pediu. A ponta da chain pode avançar enquanto você pagina, e seus resultados continuam descrevendo o mesmo ponto no tempo, até 10.000 contas por página.
Por que isso importa
Posses em um ponto específico do tempo se tornam uma query de primeira classe. O pipeline de indexação que você teria que construir e manter colapsa em uma única chamada RPC, o que libera sua equipe para trabalhar no produto em vez da infraestrutura de suporte.
Isso viabiliza trabalhos que antes eram penosos:
- Snapshots de portfólio e PnL em qualquer momento histórico
- Cost basis e relatórios fiscais atrelados a slots ou datas específicas
- Trabalho de disputa, forense e resposta a incidentes, como mostrar o que uma wallet possuía no bloco antes de ser drenada
- Pipelines de analytics e indexação que precisam de estado histórico preciso sem replay
Verificamos os resultados contra o ground truth on-chain durante os testes. Queries históricas amostradas bateram exatamente com os saldos e lamports da chain, incluindo histórico profundo como um saldo de KIN no slot 80.000.000.
Primeiros passos
O método está disponível no endpoint padrão do Solana mainnet, então se você já envia Solana RPC através da Alchemy pode chamá-lo com sua API key existente. Aponte para https://solana-mainnet.g.alchemy.com/v2/{ALCHEMY_API_KEY}, adicione um slot, e leia as posses de volta.
Veja o Solana API quickstart para configurar uma key e enviar sua primeira requisição.
FAQ
O que o getTokenAccountsByOwnerAtSlot faz?
Ele retorna as contas de token de uma wallet Solana, com saldos e lamports, referentes a um slot passado que você especifica. Tem o mesmo formato do getTokenAccountsByOwner, mais um parâmetro slot.
O que são SPL Token e Token-2022?
São os dois padrões de token da Solana. SPL Token é o original, que cobre praticamente todo token conhecido na rede. Token-2022 é a versão mais nova, que adiciona recursos opcionais como taxas de transferência e saldos confidenciais. O método cobre ambos.
Qual a diferença em relação ao getTokenAccountsByOwner?
getTokenAccountsByOwner retorna apenas as posses atuais. getTokenAccountsByOwnerAtSlot responde a mesma pergunta em qualquer slot passado, lendo de um índice histórico em vez do estado ao vivo do node.
Preciso de um node arquival ou um indexador customizado?
Não. O método lê um índice histórico pré-construído, então você não precisa rodar infraestrutura arquival nem reproduzir o histórico de transações você mesmo.
Posso consultar o portfólio completo de uma wallet, não só um token?
Sim, mas não em uma única chamada programId se a wallet possuir ambos os padrões. Escope por mint para um único token, ou por programId para todas as contas sob aquele program em um slot. SPL Token e Token-2022 usam program IDs diferentes, então para um portfólio completo é preciso consultar ambos e combinar as respostas.
Como a paginação permanece precisa conforme a chain avança?
O pageKey fixa o slot da sua query, então os resultados permanecem consistentes entre páginas mesmo com a chegada de novos blocos, até 10.000 contas por página.
Newsletter da Alchemy
Seja o primeiro a saber sobre lançamentos
Assine nossa newsletter
Receba as últimas atualizações de produtos e recursos da Alchemy
Ao inserir seu endereço de e-mail, você concorda em receber nossas comunicações de marketing e atualizações de produtos. Você reconhece que a Alchemy processa as informações que recebemos de acordo com nosso Aviso de Privacidade. Você pode cancelar a inscrição a qualquer momento.
Artigos relacionados

Glamsterdam: o guia completo para desenvolvedores de Ethereum
Glamsterdam já está na Sepolia. O guia completo sobre o que isso significa para desenvolvedores e como a Alchemy se preparou para a atualização da rede.

Em qual provedor de RPC você deve construir em Tóquio?
Comparamos cinco dos provedores de RPC que atendem Tóquio em cinco chains. Veja como eles se comparam e onde as diferenças importam para equipes sensíveis à latência.

Arquitetando leituras Solana RPC para velocidade e confiabilidade líderes do setor
A Alchemy tem a menor latência de leitura Solana: 9,21 ms, cerca de 26% mais rápido que o próximo provedor.