Como monitorar transações em blockchains na prática
Observar um charge, ou "observe a charge" como chamamos no dia a dia, é basicamente acompanhar o status de uma transação blockchain em tempo real. Não tem muito mistério, mas tem detalhes que atrapalham quem não conhece o funcionamento interno. Eu comecei a trabalhar com isso em 2021, acompanhando pagamentos em Ethereum e BSC. O problema é que a maioria das ferramentas mostra só o estado final — confirmada ou não. Você fica no escuro durante todo o processo de confirmação.
Por que usar observe a charge no seu fluxo
O principal uso prático é quando você precisa saber se um pagamento foi realmente processado antes de liberar um serviço. Sem monitoramento ativo, você depende do webhook da exchange ou da carteira, que muitas vezes chega atrasado ou nem chega. Eu tenho um caso concreto aqui. Em março de 2023, estava integrando um sistema de pagamento em Polygon para uma plataforma de SaaS. O cliente pagou, o gateway disse que estava pendente, e eu precisei esperar quase 40 minutos para ver a confirmação. Quase cancelamos o contrato porque o sistema parecia quebrado.
A solução foi implementar um polling ativo usando nodes próprios. Em vez de confiar nos webhooks, eu fazia requisições a cada 3 segundos para a API do node até a transação ser confirmada. O tempo médio de resposta caiu para menos de 15 segundos na maioria das vezes.
Configurando o monitoramento passo a passo
Você precisa de três coisas básicas: acesso a um node Ethereum (ou compatible), credenciais de API e um script de polling. Os nodes pagos custam entre 50 e 200 dólares por mês dependendo da taxa de requisições. Passo 1: Escolha o provider. Alchemy, Infura e QuickNode oferecem tiers gratuitos limitados. Para produção, eu recomendo Alchemy ou FluxNodes porque a latência é menor e o suporte a traces de transação é mais confiável.
Passo 2: Obtenha as credenciais. Crie uma conta, vá em API Keys e gere uma key com acesso ao network que você precisa. Anote tanto a URL RPC quanto a key. Sem esses dois dados, o código não funciona. Passo 3: Implemente o polling. O código básico segue este padrão:
const RPC_URL = 'https://...';
async function checkTx() {
const res = await fetch(RPC_URL, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
jsonrpc: '2.0',
method: 'eth_getTransactionReceipt',
params: [TX_HASH],
id: 1
})
});
const data = await res.json();
return data.result?.status === '0x1';
}
setInterval(async () => {
const confirmed = await checkTx();
console.log('Status:', confirmed ? 'confirmado' : 'pendente');
if (confirmed) clearInterval(interval);
}, 3000);
Esse script faz polling a cada 3 segundos. Quando o status volta como 0x1, a transação foi confirmada e você pode parar o intervalo. Funciona para Ethereum, Polygon, BSC e qualquer chain compatível com EVM.
Detalhes técnicos que ninguém conta
A primeira coisa confusa é que eth_getTransactionReceipt retorna o status, mas não garante que os fundos chegaram ao destino final. Em redes com congestão, uma transação pode ser confirmada mas ter seu estado pending por causa de reorganizações de bloco. Eu aprendi isso na marra quando perdi aproximadamente 0.3 ETH em uma reorg em 2022. A transação apareceu como confirmada no meu script, liberei o serviço, e quatro blocos depois a chain reorganizou e a transação desapareceu.
A workaround que uso hoje é adicionar um contador de confirmações. Em vez de confiar em uma confirmação, espero pelo menos 12 blocos para Ethereum mainnet, ou 64 para Polygon. Isso elimina quase totalmente o risco de reorg. Outro detalhe importante: o campo gasUsed no receipt mostra quanto gas foi efetivamente consumido, mas não o preço do gas no momento da execução. Se você precisa calcular o custo exato da transação, precisa combinar com eth_getBlockByNumber para pegar o base fee do bloco.
👉 Clique no botão abaixo para saber mais sobre o assunto!
Alternativas ao polling tradicional
Se você está processando alto volume, polling não escala bem. Cada requisição custa dinheiro e tempo de CPU. A alternativa são os webhooks do próprio provider — Alchemy e QuickNode oferecem essa feature em tiers pagos. Com webhooks, você registra uma URL de callback e o provider notifica quando o status muda. É mais barato e mais rápido, mas tem limitações: você perde controle do timing e depende da infraestrutura do provider funcionar corretamente.
Eu uso uma combinação dos dois. Pollo nos primeiros 30 segundos pós-submissão, depois faço fallback para webhook. Dessa forma cobro os casos onde o polling encontra confirmação rápido e também os onde o webhook chega primeiro.
Erros comuns ao monitorar charges
O erro mais frequente é confundir transação pendente com transação falha. Quando o nonce já foi usado mas o receipt ainda não aparece, a transação está em mempool, não quebrada. Fazer polling contínuo resolve isso em segundos na maioria das chains. Outro erro é não tratar o caso de transaction not found. Alguns nodes retornam null quando a transação ainda não foi minerada, e seu código pode quebrar se não verificar isso explicitamente.
Eu adicionei um timeout de 5 minutos no meu sistema. Se após 5 minutos de polling a transação não aparecer, registro como falha e entro em contato com o usuário para verificar manualmente. Isso elimina falsos positivos na maioria dos casos.
Custos e limitações reais
Polling a cada 3 segundos custa aproximadamente 20.000 requisições por dia por transação. Com um plano gratuito de 100.000 requisições mensais, você consegue monitorar cerca de 150 transações simultâneas. Para volumes maiores, precisa de plano pago. Se você está construindo um sistema que processa milhares de transações diárias, considere usar nodes dedicados ou APIs batch. QuickNode eAlchemy oferecem endpoints otimizados para alto volume com latência menor.
Também existe o limite de rate limit. A maioria dos providers gratuitos permite 10 requisições por segundo. Se seu polling exceder isso, você recebe erro 429 e precisa implementar backoff exponencial. Sem isso, sua conta pode ser suspensa temporariamente.
Quando observar um charge não funciona
Existem cenários onde o monitoramento ativo simplesmente não resolve. Se a transação foi enviada com gas price muito baixo, ela pode ficar presa na mempool por horas ou dias. Nenhum polling vai resolver isso — a única saída é substituição de transação (RBF) ou cancelled com fee maior. Outro caso é quando o destinatário usa contratos que exigem confirmações múltiplas, como multisigs. O receipt mostra a transação confirmada, mas o estado do contrato ainda não foi atualizado porque falta assinaturas. Nesse caso, você precisa monitorar eventos do contrato, não só o receipt.
Finalmente, chains com finalidade probabilística como Solana ou Avalanche precisam de abordagem diferente. O conceito de "confirmação" é distinto — aqui se usa o número de virações (rotations) ou validadores que assinaram o bloco, não o depth de blocos. Se seu projeto envolve multiple chains, considere usar uma biblioteca como viem ou ethers.js que abstrai essas diferenças. Desenvolver do zero para cada chain gasta tempo que poderia ser usado em features reais do produto.
Aprendi isso depois de perder três semanas implementando suporte a Solana manualmente. Uma biblioteca consolidada resolveu em dois dias. Nem sempre construir do zero é a melhor resposta.