Como enviar transações cripto em JavaScript: Bitcoin, Ethereum, Litecoin, Dogecoin e mais com ChainGate

Um guia prático em JavaScript para enviar Bitcoin, Ethereum, Avalanche, Litecoin, Dogecoin e Bitcoin Cash a partir de um único SDK — por ChainGate.

Bitcoin, Ethereum, Avalanche, Litecoin, Dogecoin and Bitcoin Cash — +6 chains, one JavaScript transfer() call

Ler dados on-chain a partir do JavaScript sempre foi a metade chata do trabalho. Pegar um saldo Bitcoin limpo — saldo confirmado e pendente, do jeito que um explorer mostra — geralmente significa subir o seu próprio indexer ou bater contra uma API pública instável. Listar os NFTs e tokens que um endereço Ethereum ou EVM possui obriga a costurar três ou quatro endpoints de explorer, cada um com seu próprio schema, seus rate limits e campos faltando. E na hora em que você quer realmente fazer broadcast de uma transação, está de volta ao bitcoinjs-lib para Bitcoin, ethers ou viem do lado EVM e a um fork meio mantido para Dogecoin e Litecoin. ChainGate cobre tudo isso num único SDK.

ChainGate junta todo esse trabalho num único SDK em JavaScript. Pensado como um SDK multi-chain para wallets, a mesma forma de chamada envia Bitcoin, Ethereum, Avalanche (e qualquer cadeia EVM), Litecoin, Dogecoin e Bitcoin Cash, lê saldos de endereços e lista os assets que estão em qualquer endereço. O mesmo pacote roda em Node.js e no navegador sem mexer no código — todas as primitivas crypto vêm de forma nativa, sem polyfills.

Abaixo o envio básico em cinco linhas. O resto do guia percorre o mesmo padrão em cada cadeia e depois adiciona estimativa de fees e consulta de saldo antes do broadcast:

import { ChainGate, importWallet } from 'chaingate';

const cg = new ChainGate({ apiKey: 'your-api-key' });
const wallet = importWallet({ phrase: process.env.MNEMONIC });
const btc = cg.connect(cg.networks.bitcoin, wallet);

const tx = await btc.transfer(cg.networks.bitcoin.amount('0.001'), 'bc1qRecipient...');
await tx.signAndBroadcast();

A versão curta

  • Um SDK, todas as cadeias. A mesma API transfer() cobre Bitcoin, Ethereum, Avalanche, Litecoin, Dogecoin, Bitcoin Cash e qualquer rede compatível com EVM.
  • Roda sem mudanças em Node.js 22+ e navegadores modernos — sem configurar polyfills de Buffer ou crypto.
  • Fees, saldo e broadcast já vêm embutidos — não é preciso uma segunda biblioteca para nada disso.
  • A assinatura sempre acontece localmente. Sua chave privada não sai do SDK.

1. Setup: instalar e inicializar a ChainGate

Escolha seu gerenciador de pacotes. O SDK é publicado como um único pacote npm — instale uma vez e dá para enviar Bitcoin, Ethereum e o resto a partir do mesmo import, com tipos incluídos:

# pick your package manager
npm install chaingate
pnpm add chaingate
yarn add chaingate

Em seguida pegue uma API key gratuita no dashboard da ChainGate. O cadastro leva um minuto e o tier gratuito é o suficiente para colocar um protótipo em produção. Inicialize o cliente com essa key uma vez e reaproveite para cada cadeia:

import { ChainGate } from 'chaingate';

const cg = new ChainGate({ apiKey: process.env.CHAINGATE_API_KEY });

Mesmo código no Node.js e no navegador. O pacote funciona em Node 22+, navegadores modernos (Vite, Next.js, Webpack 5+) e Bun de fábrica, então a mesma biblioteca blockchain Node.js que você importa no servidor é a que roda no navegador do usuário. Primitivas crypto como Buffer e randomBytes vêm nativas dentro do SDK — nada para polyfillar, nada para configurar.

Os tipos de TypeScript já vêm embutidos. Não existe um pacote @types/chaingate porque não precisa — toda classe, método e evento público é totalmente tipado na origem.

2. Enviar Bitcoin, Litecoin, Dogecoin e Bitcoin Cash

Bitcoin, Litecoin, Dogecoin e Bitcoin Cash compartilham o mesmo modelo contábil — UTXOs. O saldo de uma wallet é a soma das saídas de transações ainda não gastas (unspent transaction outputs) presas aos seus endereços. Para enviar fundos, a wallet escolhe UTXOs suficientes para cobrir o valor, monta uma nova transação que os consome como inputs, manda ao destinatário uma saída, devolve o troco para si mesma como output de change e paga um fee em satoshis por kilobyte (ou o equivalente por cadeia).

ChainGate gerencia cada um desses passos — seleção de UTXOs, output de change, tier de fee e assinatura — atrás de uma única chamada transfer(). Você passa endereço e valor, recebe de volta uma transação assinada pronta para broadcast.

Enviar Bitcoin pelo Node.js ou no navegador

O exemplo base. Conecte sua wallet à rede do Bitcoin, crie a transferência, escolha um tier de fee e faça broadcast:

import { ChainGate, importWallet, NotEnoughFundsError } from 'chaingate';

const cg = new ChainGate({ apiKey: process.env.CHAINGATE_API_KEY });
const wallet = importWallet({ phrase: process.env.MNEMONIC });

const btc = cg.connect(cg.networks.bitcoin, wallet);
const amount = cg.networks.bitcoin.amount('0.001'); // 0.001 BTC

try {
  const tx = await btc.transfer(amount, 'bc1qRecipient...');
  tx.setFee(tx.recommendedFees().normal);

  const broadcast = await tx.signAndBroadcast();
  console.log('BTC txid:', broadcast.transactionId);
} catch (err) {
  if (err instanceof NotEnoughFundsError) {
    console.error('Not enough BTC for this transfer + fee');
  }
  throw err;
}

Para apontar para a testnet em desenvolvimento, troque cg.networks.bitcoin por cg.networks.bitcoinTestnet — o resto do código fica igual.

Enviar Litecoin pelo Node.js ou no navegador

Mesmo código, rede diferente. O diff em relação ao snippet de Bitcoin é literalmente um identificador:

const ltc = cg.connect(cg.networks.litecoin, wallet);
const amount = cg.networks.litecoin.amount('0.1'); // 0.1 LTC

const tx = await ltc.transfer(amount, 'ltc1qRecipient...');
tx.setFee(tx.recommendedFees().normal);
await tx.signAndBroadcast();

Litecoin usa endereços SegWit ltc1q… por padrão e confirma blocos a cada dois minutos e meio — cerca de quatro vezes mais rápido que Bitcoin —, o que o torna popular para pagamentos de baixo valor onde a velocidade de liquidação importa mais que a profundidade de segurança.

Enviar Dogecoin pelo Node.js ou no navegador

Mesmo diff, cadeia diferente:

const doge = cg.connect(cg.networks.dogecoin, wallet);
const amount = cg.networks.dogecoin.amount('100'); // 100 DOGE

const tx = await doge.transfer(amount, 'DRecipientAddress...');
tx.setFee(tx.recommendedFees().normal);
await tx.signAndBroadcast();

O ecossistema JavaScript do Dogecoin ficou para trás em relação ao resto da família UTXO. A maioria dos forks populares de bitcoinjs-lib não é atualizada há anos e as poucas alternativas mantidas são privadas. ChainGate é uma das poucas opções entregando suporte de Dogecoin em qualidade de produção em JavaScript hoje.

Enviar Bitcoin Cash pelo Node.js ou no navegador

Bitcoin Cash usa endereços CashAddr por padrão, mas o SDK aceita também o formato legacy — pode colar qualquer um dos dois em transfer() e a rede vai confirmar:

const bch = cg.connect(cg.networks.bitcoincash, wallet);
const amount = cg.networks.bitcoincash.amount('0.05'); // 0.05 BCH

// CashAddr or legacy — both work
const tx = await bch.transfer(amount, 'bitcoincash:qpRecipient...');
tx.setFee(tx.recommendedFees().normal);
await tx.signAndBroadcast();

A validação de endereço é bidirecional: cg.networks.bitcoincash.isValidAddress() retorna true para ambos os formatos, então você não precisa normalizar a entrada do usuário antes de enviar.

Enviar UTXO no navegador

Os quatro snippets UTXO acima rodam sem alteração num bundle Vite, Next.js ou Webpack 5 — o mesmo import funciona no client e a mesma wallet assina localmente sem chamar a API.

Uma nota sobre segurança: nunca carregue chaves privadas de produção diretamente num frontend. Ou mantenha a assinatura no servidor e envie só o broadcast pelo navegador, ou faça com que o usuário forneça a chave por meio de um fluxo tipo wallet que ele controle.

3. Enviar Ethereum e cadeias EVM

O modelo de contas do Ethereum é diferente — não há UTXOs, só um endereço com saldo e um nonce que cresce monotonicamente. ChainGate esconde essa diferença atrás da mesma chamada transfer() que você usou no Bitcoin. As diferenças (gerenciamento de nonce, base fee + tip do EIP-1559, gas limit) são calculadas para você:

const eth = cg.connect(cg.networks.ethereum, wallet);
const amount = cg.networks.ethereum.amount('0.01'); // 0.01 ETH

const tx = await eth.transfer(amount, '0xRecipient...');
tx.setFee(tx.recommendedFees().normal);

const broadcast = await tx.signAndBroadcast();
console.log('ETH txHash:', broadcast.transactionId);

Enviar Avalanche com Node.js ou no navegador

A C-Chain do Avalanche está cabeada como rede de primeira classe ao lado do Ethereum — mesma forma de chamada, mesma wallet, valores em AVAX. O diff em relação ao snippet do Ethereum é um único identificador:

const avax = cg.connect(cg.networks.avalanche, wallet);
const amount = cg.networks.avalanche.amount('1'); // 1 AVAX

const tx = await avax.transfer(amount, '0xRecipient...');
tx.setFee(tx.recommendedFees().normal);
await tx.signAndBroadcast();

A C-Chain finaliza blocos em cerca de dois segundos e usa o mesmo modelo de fees EIP-1559 do Ethereum, então as transferências de AVAX liquidam rápido e a saída de recommendedFees() tem o mesmo formato. Isso faz da Avalanche uma escolha popular para pagamentos de alto throughput em que o gas do Ethereum tiraria o usuário do jogo.

Mesma wallet, mesmo SDK, todas as cadeias EVM. As URLs RPC hospedadas cobrem Polygon, Arbitrum, Base, BNB Chain e Sonic de fábrica; para qualquer outra rede EVM — Optimism, Linea, Scroll, Gnosis, seu próprio nó, uma testnet — passe a URL JSON-RPC direto para evmRpc(). Enviar POL na Polygon é um diff de uma linha:

const polygon = cg.networks.evmRpc({
  rpcUrl: cg.rpcUrls.polygon,
  chainId: 137,
  name: 'Polygon',
  symbol: 'POL',
});

const pol = cg.connect(polygon, wallet);
const amount = polygon.amount('5'); // 5 POL

const tx = await pol.transfer(amount, '0xRecipient...');
tx.setFee(tx.recommendedFees().normal);
await tx.signAndBroadcast();

O nonce é gerenciado automaticamente. O SDK lê o último nonce pendente do RPC escolhido antes de assinar, então você não precisa controlá-lo. A construção do fee usa por padrão EIP-1559 (maxFeePerGas + maxPriorityFeePerGas) nas cadeias que suportam e cai para gas pricing legacy nas que não.

O chainId que você passa para evmRpc() precisa ser o que o próprio endpoint RPC informa, senão o SDK vai assinar para a rede errada. A lista de chain IDs das redes EVM tem o número de Polygon, Arbitrum, Base, Optimism e outras 35 redes e testnets, e mostra como lê-lo direto de qualquer URL RPC.

Se o nó responder a um broadcast com "nonce too low", "replacement transaction underpriced" ou "insufficient funds for gas * price + value", o guia sobre erros de transação no Ethereum explica o que cada mensagem significa e quais delas custam gas.

O suporte ao navegador é idêntico ao das cadeias UTXO. Esse é o código que você colocaria atrás de um botão 'Send' numa dApp.

4. Estimar fees antes de enviar

Sempre mostre o fee antes de fazer broadcast. Usuários odeiam surpresas, transações travadas custam tempo e um passo de 'revisar e confirmar' transforma um fluxo de UI de tiro único em algo em que o usuário realmente confia.

ChainGate expõe o mesmo método recommendedFees() em cada cadeia — devolve quatro tiers (low, normal, high, maximum) com os números que cada tier precisa. No Bitcoin você recebe uma taxa feePerKbSat e o total estimado em satoshis; no Ethereum e em outras cadeias EVM você recebe maxFeePerGas e maxPriorityFeePerGas do EIP-1559 como bigint em wei, mais uma janela estimada de confirmação:

// Bitcoin — fee rate in sat/kB, plus the total estimated fee in satoshis
const btcTx = await btc.transfer(cg.networks.bitcoin.amount('0.01'), 'bc1q...');
const btcFees = btcTx.recommendedFees();

console.table({
  low:    { satPerKb: btcFees.low.feePerKbSat,    feeSat: btcFees.low.estimatedFeeSat,    enough: btcFees.low.enoughFunds },
  normal: { satPerKb: btcFees.normal.feePerKbSat, feeSat: btcFees.normal.estimatedFeeSat, enough: btcFees.normal.enoughFunds },
  high:   { satPerKb: btcFees.high.feePerKbSat,   feeSat: btcFees.high.estimatedFeeSat,   enough: btcFees.high.enoughFunds },
});

// Ethereum — EIP-1559 numbers in gwei
const ethTx = await eth.transfer(cg.networks.ethereum.amount('0.1'), '0x...');
const ethFees = ethTx.recommendedFees();
const toGwei = (wei) => Number(wei) / 1e9;

console.table({
  low:     { gwei: toGwei(ethFees.low.maxFeePerGas),     sec: ethFees.low.estimatedConfirmationSecs },
  normal:  { gwei: toGwei(ethFees.normal.maxFeePerGas),  sec: ethFees.normal.estimatedConfirmationSecs },
  high:    { gwei: toGwei(ethFees.high.maxFeePerGas),    sec: ethFees.high.estimatedConfirmationSecs },
  maximum: { gwei: toGwei(ethFees.maximum.maxFeePerGas), sec: ethFees.maximum.estimatedConfirmationSecs },
});

O padrão que funciona em produção: monte a transação, chame recommendedFees(), mostre os quatro tiers para o usuário, deixe ele escolher e então chame signAndBroadcast(). O objeto da transação fica em memória entre estimar e fazer broadcast — não precisa reconstruir nada.

5. Consultar saldo antes de enviar

Uma consulta de saldo merece ficar no topo de qualquer fluxo de envio. Pega erros de digitação, evita gastar gas em uma transação que vai falhar e dá ao usuário um número que ele pode conferir. Cada cadeia expõe o mesmo one-liner — passe um endereço (ou use a wallet conectada) e receba o saldo confirmado e, nas cadeias que suportam, a parte pendente:

// Ethereum — confirmed balance + live USD price
const eth = cg.connect(cg.networks.ethereum, wallet);
const ethBalance = await eth.addressBalance();
const ethUsd = await ethBalance.confirmed.toCurrency('usd');
console.log(`${ethBalance.confirmed.base()} ETH ($${ethUsd})`);

// Bitcoin — confirmed and unconfirmed split
const btc = cg.connect(cg.networks.bitcoin, wallet);
const btcBalance = await btc.addressBalance();
console.log(`Confirmed:   ${btcBalance.confirmed.base()} BTC`);
console.log(`Unconfirmed: ${btcBalance.unconfirmed.base()} BTC`);

Combinada com a estimativa de fee, o pre-flight completo são três chamadas — saldo, fee e depois envio. Conecte tudo uma vez e cada fluxo de envio do seu app ganha a mesma validação prévia de graça, seja consultando um saldo cripto pelo Node.js no servidor ou pelo navegador.

6. ChainGate vs bitcoinjs-lib, ethers e outras alternativas

ChainGate não tenta substituir todas as bibliotecas de baixo nível anteriores. Cada uma tem seu papel claro. Veja como os trade-offs ficam quando você precisa enviar transações em mais de uma cadeia:

CapacidadeChainGatebitcoinjs-libethers / viemImplementação própria
Cadeias suportadasBTC, ETH, AVAX+EVM, LTC, DOGE, BCHApenas BitcoinApenas EVM1 por biblioteca
Linhas para enviar BTC~5~40+n/avaria
Pronto para navegadorSim — de fábricaExige polyfillsSimVaria
Estimativa de fees embutidaSimNãoParcialNão
Tipos de TypeScriptFirst-classComunidadeSimVaria

Continue com bitcoinjs-lib ou ethers quando precisar de controle byte a byte sobre o formato da transação, ou quando seu app fala com uma única cadeia e o tamanho do bundle é o fator decisivo. Mude para ChainGate quando estiver lidando com mais de uma cadeia, contra um prazo apertado ou tocando um time pequeno que não pode se dar ao luxo de especializar pessoas por blockchain.

7. Preços e tier gratuito

O tier gratuito é generoso de propósito — todos os planos, incluindo o gratuito, vêm com o SDK completo: saldos, listagens de assets, estimativa de fees, assinatura e broadcast em cada cadeia que suportamos. É o suficiente para entregar um protótipo, tocar um projeto pessoal ou colocar uma ferramenta interna em produção. Sem cartão no cadastro.

Os planos pagos sobem os rate limits e adicionam suporte prioritário e capacidade de burst. O upgrade é um clique dentro do dashboard.

Veja a página de planos para os números atualizados e o caminho de upgrade.

8. Por onde seguir

Você já tem o modelo: um SDK, várias cadeias e a mesma forma de cinco linhas em cada uma. Daqui em diante, a documentação cobre o resto da superfície — assinatura de mensagens, transferências de ERC-20, envios de NFT, histórico de transações decodificado. Os exemplos no GitHub são um bom ponto de partida com receitas end-to-end que dá para copiar. E o dashboard da API está a um clique quando você quiser pegar uma key e colocar algo no ar. Para entender melhor a mecânica por trás de um fee, o guia complementar sobre gas no Ethereum mostra de onde realmente saem os números do recommendedFees(). O guia sobre hashes de transação explica como é o transactionId que o signAndBroadcast() devolve em cada rede e como consultá-lo em um block explorer.

Perguntas frequentes

A ChainGate guarda minhas chaves privadas?
Não. A construção da wallet, a derivação de chaves e a assinatura rodam localmente no seu dispositivo. A API da ChainGate só lida com chamadas de leitura e faz broadcast de transações já assinadas — sua seed phrase e sua chave privada nunca saem do SDK.
Posso usar ChainGate no navegador?

Sim — todos os exemplos deste guia rodam sem alteração num bundle Vite, Next.js ou Webpack 5. O SDK traz a sua própria crypto compatível com navegador, então não há nada a mais para instalar.

Quais redes são suportadas?

ChainGate oferece suporte de API completa para Bitcoin, Bitcoin Testnet, Litecoin, Dogecoin, Bitcoin Cash, Ethereum e Avalanche, endpoints JSON-RPC hospedados para Polygon, Arbitrum, Base, BNB Chain e Sonic, e suporte de bring-your-own-RPC para qualquer outra cadeia EVM — incluindo Optimism, Linea, Scroll, Gnosis, testnets e nós auto-hospedados. A matriz completa está na documentação.

Posso enviar transações em testnet?

Sim — não tem flag especial de testnet. Passe a rede testnet para a mesma chamada cg.connect() que você usa em mainnet: no Bitcoin é cg.networks.bitcoinTestnet; para uma testnet EVM, passe a URL JSON-RPC e o chain ID da testnet para cg.networks.evmRpc({ rpcUrl, chainId, name, symbol }). O resto do código é igual aos exemplos de mainnet deste guia.

O que acontece se uma transação falha?

O SDK expõe um erro tipado que dá para capturar e tratar. A maior parte dos problemas pré-broadcast é recuperável — o objeto da transação é reconstruído com nonce novo ou nova seleção de UTXOs no retry, então uma segunda tentativa normalmente passa.

ChainGate é open source?

O SDK em JavaScript que assina e faz broadcast na sua máquina está publicado no GitHub sob licença MIT — leia o código, copie para o seu repo ou faça um fork. A API da ChainGate por trás é um serviço gerenciado que cuida do resto pra você. A maior parte dos times usa o SDK open source com a API hospedada, mas dá para apontar o SDK para qualquer URL RPC que você controle se preferir hospedar a própria infraestrutura.

Por que o ChainGate precisa de uma API key?
A API key autentica as chamadas ao backend do ChainGate, que é o que cobre as partes que o SDK não consegue fazer sozinho — processa as requisições JSON-RPC para a cadeia que você está usando, lê UTXOs e balances e faz broadcast das transações assinadas. A assinatura continua acontecendo localmente com a sua wallet; a key só autoriza o tráfego de leitura e de broadcast que passa pela infraestrutura do ChainGate. O plano gratuito gera uma key no dashboard sem cartão de crédito.

Construa com ChainGate

Leve estas ideias para o código — a ChainGate te oferece wallets, transações e RPC gerenciado para Ethereum e mais de 20 blockchains com uma única instalação.