WEB3DEV

Cover image for Como obter logs (ou registros) de transação na Solana
Isabela Curado Nehme
Isabela Curado Nehme

Posted on

Como obter logs (ou registros) de transação na Solana

27 de outubro de 2022

Visão geral

Você já precisou puxar todas as transações associadas com uma carteira? Quer ver todas as transações de cunhagem associadas com uma Candy Machine? Ou talvez ver o histórico de transações de um NFT? O método getSignaturesForAddress da Solana é uma ferramenta versátil que faz com que obter histórico de transações seja leve.

Aqui está um vídeo, se você preferir assistir:
https://www.youtube.com/watch?v=pN-bx6NfDmg

O que você vai fazer

Neste guia, você mergulhará no mundo excitante das transações em Solana! Você irá construir um script simples que pode consultar um endereço (carteira, ID de programa, cunhagem de token, etc.) e encontrar todo o histórico de transações associados a ele.

O que você vai precisar

  • Nodejs (versão 16.15 ou superior)
  • Yarn instalado
  • Solana web3
  • Experiência com transações básicas em Solana. Para aprimorar seus conhecimentos, leia nosso guia para iniciantes sobre How to Send a Transaction on Solana (Como enviar uma transação na Solana)
  • Conhecimento de Javascript

Vamos começar!

Configure seu ambiente

Crie um novo diretório de projeto e arquivo, log.js, no seu terminal com:

mkdir get_sol_tx
cd get_sol_tx
echo > log.js
Enter fullscreen mode Exit fullscreen mode

Instale as dependências da Solana web3:

yarn init -y
yarn add @solana/web3.js
Enter fullscreen mode Exit fullscreen mode

ou

npm init -y
npm install --save @solana/web3.js
Enter fullscreen mode Exit fullscreen mode

Abra log.js em um editor de código de sua escolha e, na linha 1, requeira @solana/web3.js e armazene-o em uma constante, solanaWeb3:

const solanaWeb3 = require('@solana/web3.js');
Enter fullscreen mode Exit fullscreen mode

Declare um endereço que você gostaria de buscar:

const solanaWeb3 = require('@solana/web3.js');
Enter fullscreen mode Exit fullscreen mode

Observação: pode ser qualquer endereço válido na Solana (por exemplo, endereço de carteira, endereço de cunhagem, endereço de programa). Você pode usar ‘vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg'‘ como um exemplo se você ainda não tiver uma.

Tudo bem, estamos prontos para começar a cozinhar!

Estabeleça uma conexão com o seu RPC na QuickNode

Para construir na Solana, você precisará de um endpoint de API para se conectar à rede. Você é convidado a usar nós públicos ou implantar e gerenciar sua própria infraestrutura. Contudo, se quiser ter tempos de resposta 8x mais rápidos, você pode deixar o trabalho pesado para nós. Veja por que mais de 50% dos projetos na Solana escolhem a QuickNode e se inscreva de graça, 7 dias de experimentação aqui. Vamos lançar nosso nó na Solana Devnet, mas você pode lançar o nó que atenda às suas necessidades. Copie o link do provedor HTTP:

Navegue de volta ao log.js e crie uma constante endpoint e atribua a ela o url da QuickNode. Na linha seguinte, passe essa constante como parâmetro para a função Connection (Conexão) e armazene-a em outra constante chamada solanaConecction:

const endpoint = 'https://example.solana-devnet.quiknode.pro/000000/';
const solanaConnection = new solanaWeb3.Connection(endpoint);
Enter fullscreen mode Exit fullscreen mode

Excelente! Você está pronto para construir sua função de pesquisa.

Crie uma consulta de transação

O método getSignaturesForAddress fará muito do trabalho pesado aqui. Aqui está como vai funcionar:

Ele aceitará dois parâmetros:

  • Endereço para pesquisa (obrigatório): a chave pública que você quer buscar.
  • Opções (opcional): um objeto que inclui 3 entradas opcionais:
  • antes: comece pesquisando de trás para frente em um tempo antes de uma assinatura de transação específica
  • depois: comece pesquisando para frente em um tempo depois de uma assinatura de transação específica
  • limite: número máximo de transações para retornar (observe que o valor máximo e padrão é 1.000)

Ele retornará uma promessa para uma matriz de ConfirmedSignatureInfo, um objeto de tipo que inclui as informações chave da transação:

  • assinatura (ID da transação);
  • slot e blockTime (tempo de bloco) (para ver quando a transação foi processada);
  • err (se houver erros);
  • memo (se houver memorandos associados à transação).

Defina uma nova função async, getTransactions, que recebe dois parâmetros: address e numTx.

Dentro da nossa função, chame o método getSignaturesForAddress em uma nova instância da solanaConnection e grave a saída em uma variável transactionList:

const getTransactions = async(address, numTx) => {
    const pubKey = new solanaWeb3.PublicKey(address);
    let transactionList = await solanaConnection.getSignaturesForAddress(pubKey, {limit:numTx});
}
Enter fullscreen mode Exit fullscreen mode

Isto deve nos fornecer uma matriz de todo o histórico de transações que atenda aos nossos critérios de pesquisa.

Vamos registrar os resultados de uma maneira que seja fácil de ler.

Dentro da getTransactions, crie um loop forEach para registrar informações sobre cada transação:

const getTransactions = async(address, numTx) => {
    const pubKey = new solanaWeb3.PublicKey(address);
    let transactionList = await solanaConnection.getSignaturesForAddress(pubKey, {limit:numTx});
    transactionList.forEach((transaction, i) => {
        const date = new Date(transaction.blockTime*1000);
        console.log(`Transaction No: ${i+1}`);
        console.log(`Signature: ${transaction.signature}`);
        console.log(`Time: ${date}`);
        console.log(`Status: ${transaction.confirmationStatus}`);
        console.log(("-").repeat(20));
    })
}
Enter fullscreen mode Exit fullscreen mode

Execute seu código!

Se tudo estiver configurado corretamente, você deve ser capaz de chamar sua função e ver alguns resultados! Adicione isto ao final do log.js:

getTransactions(searchAddress,3);
Enter fullscreen mode Exit fullscreen mode

E agora no seu tipo de terminal:

node log.js
Enter fullscreen mode Exit fullscreen mode

Você deve ver algo assim:

Uau! Muito fácil, né? Sinta-se livre para testar e experimentar algumas carteiras diferentes, um endereço de cunhagem de NFT, e uma ID de Candy Machine. Você pode observar que o método deve produzir resultados semelhantes, o que o torna realmente útil para várias aplicações diferentes.

Parabéns! Você conseguiu obter transações com sucesso… Você pode parar aqui, mas se quiser ver o que mais podemos fazer com essa assinatura de transação, continue lendo! 👇

Analisando a transação

Então, temos algumas informações básicas úteis sobre nosso histórico de transações, mas o que cada transação faz? Podemos usar o método getParsedTransaction da Solana para nos fornecer muitos detalhes adicionais.

O método getParsedTransaction receberá uma assinatura de transação confirmada ou finalizada e retornará um objeto ParsedTransactionWithMeta:

export type ParsedTransactionWithMeta = {
    /** O slot durante o qual a transação foi processada */
    slot: number;
    /** Os detalhes da transação */
    transaction: ParsedTransaction;
    /** Metadados produzidos a partir da transação */
    meta: ParsedTransactionMeta | null;
    /** O timestamp unix de quando a transação foi processada */
    blockTime?: number | null;
    /** A versão da mensagem de transação */
    version?: TransactionVersion;
  };
Enter fullscreen mode Exit fullscreen mode

Há um monte de informação escondida aqui, que não abordaremos neste guia introdutório, mas nós queremos dar um exemplo de como você pode interagir com esses objetos.

Dentro da sua função getTransactions, vamos declarar duas novas variáveis: signatureList e transactionDetails. Vamos gerar uma lista de assinaturas mapeando nossa transactionList e geraremos detalhes sobre cada transação chamando essas assinaturas em getParsedTransactions:

const getTransactions = async(address, numTx) => {
    const pubKey = new solanaWeb3.PublicKey(address);
    let transactionList = await solanaConnection.getSignaturesForAddress(pubKey, {limit:numTx});

    //Adicione este código
    let signatureList = transactionList.map(transaction=>transaction.signature);
    let transactionDetails = await solanaConnection.getParsedTransactions(signatureList, {maxSupportedTransactionVersion:0});
    //--FIM do novo código 

    transactionList.forEach((transaction, i) => {
        const date = new Date(transaction.blockTime*1000);
        console.log(`Transaction No: ${i+1}`);
        console.log(`Signature: ${transaction.signature}`);
        console.log(`Time: ${date}`);
        console.log(`Status: ${transaction.confirmationStatus}`);
        console.log(("-").repeat(20));
    })
}
Enter fullscreen mode Exit fullscreen mode

Quando nossas promessas retornarem, transactionDetails produzirá uma matriz de objetos ParsedTransactionWithMeta. Vamos tentar e encontrar algumas informações úteis lá.

Digamos que estamos interessados em encontrar todos os programas ou contratos inteligentes com os quais interagimos para uma determinada transação. Dentro do nosso loop original forEach, após nossa declaração de date, vamos criar uma nova variável, transactionInstructions:

        const transactionInstructions = transactionDetails[i].transaction.message.instructions;
Enter fullscreen mode Exit fullscreen mode

Isso usará nosso índice, i, para encontrar as informações detalhadas da transação para a mesma transação que está sendo requerida no loop. Como cada transação pode ter várias instruções ou iterações de programa, precisaremos de outro loop para obter cada interação do programa em nossa transação. Dentro do nosso loop, após nosso registro de confirmationStatus, adicione isto:

        transactionInstructions.forEach((instruction, n)=>{
            console.log(`---Instructions ${n+1}: ${instruction.programId.toString()}`);
        })
Enter fullscreen mode Exit fullscreen mode

O que estamos fazendo aqui é, para cada transação, examinar cada instrução de transação e registar o nome do programa (se houver) e o ID do programa.

A função final deve ficar assim:

const getTransactions = async(address, numTx) => {
    const pubKey = new solanaWeb3.PublicKey(address);
    let transactionList = await solanaConnection.getSignaturesForAddress(pubKey, {limit:numTx});

    let signatureList = transactionList.map(transaction=>transaction.signature);
    let transactionDetails = await solanaConnection.getParsedTransactions(signatureList, {maxSupportedTransactionVersion:0});

    transactionList.forEach((transaction, i) => {
        const date = new Date(transaction.blockTime*1000);
        const transactionInstructions = transactionDetails[i].transaction.message.instructions;
        console.log(`Transaction No: ${i+1}`);
        console.log(`Signature: ${transaction.signature}`);
        console.log(`Time: ${date}`);
        console.log(`Status: ${transaction.confirmationStatus}`);
        transactionInstructions.forEach((instruction, n)=>{
            console.log(`---Instructions ${n+1}: ${instruction.programId.toString()}`);
        })
        console.log(("-").repeat(20));
    })
}
Enter fullscreen mode Exit fullscreen mode

Agora, execute seu script novamente. No seu terminal, digite:

node log.js
Enter fullscreen mode Exit fullscreen mode

Você deve ver algo assim:

Bom trabalho! Nossos resultados de transação agora incluem detalhes sobre os diferentes programas com os quais interagimos!

Se desejar, compare seus resultados com o explorador da Solana pesquisando seu endereço aqui (certifique-se de que está pesquisando na mesma rede alterando no canto superior direito da página).

Wrap Up (Enrolar)

Glórias! Você agora tem uma visão interna do mundo excitante das transações Solana!

Abordaremos mais sobre isso em um guia futuro. Mas se você estiver ansioso para continuar explorando, tente experimentar sua matriz transcantionDetails executando algumas consultas semelhantes que, em vez disso, examinam:

  • transactionDetails[i].meta
  • transactionDetails[i].transaction.message.accountKeys

Para colocar esses conceitos em prática, confira alguns outros tutoriais Solana aqui.

Se inscreva na nossa newsletter para mais artigos e guias em Solana. Sinta-se à vontade para entrar em contato conosco via Twitter se você tiver algum comentário. Você sempre pode conversar conosco em nosso servidor da comunidade Discord, apresentando alguns dos desenvolvedores mais legais que você já conheceu :)

Esse artigo foi escrito pela equipe QuickNode e traduzido por Isabela Curado Nehme. Seu original pode ser lido aqui.

Top comments (0)