
Lire des données on-chain depuis JavaScript a toujours été la moitié pénible du job. Récupérer un solde Bitcoin propre — solde confirmé et solde en attente, comme l'affiche un explorer — passe en général par faire tourner son propre indexer ou taper sur une API publique instable. Lister les NFTs et tokens que détient une adresse Ethereum ou EVM oblige à coller bout à bout trois ou quatre endpoints d'explorer, chacun avec son propre schema, ses rate limits et des champs qui manquent. Et dès qu'on veut vraiment broadcaster une transaction, on retombe sur bitcoinjs-lib pour Bitcoin, ethers ou viem côté EVM, et un fork à moitié maintenu pour Dogecoin et Litecoin. ChainGate couvre tout ça depuis un seul SDK.
ChainGate condense tout cela dans un seul SDK JavaScript. Conçu comme un SDK multi-chain pour wallets, la même forme d'appel envoie Bitcoin, Ethereum, Avalanche (et toute chaîne EVM), Litecoin, Dogecoin et Bitcoin Cash, lit les soldes d'adresse et liste les assets posés sur n'importe quelle adresse. Le même paquet tourne sous Node.js et dans le navigateur sans changement de code — chaque primitive crypto est livrée nativement, sans polyfills.
Voici l'envoi de base, en cinq lignes. Le reste du guide reprend le même pattern sur chaque chaîne, puis ajoute l'estimation des frais et la vérification du solde avant le 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();La version courte
- Un SDK, toutes les chaînes. La même API transfer() couvre Bitcoin, Ethereum, Avalanche, Litecoin, Dogecoin, Bitcoin Cash et toutes les networks compatibles EVM.
- Tourne sans modification sous Node.js 22+ et dans les navigateurs modernes — pas de polyfills Buffer ou crypto à configurer.
- Frais, solde et broadcast sont intégrés — pas de seconde bibliothèque pour chacun.
- La signature reste toujours locale. Votre clé privée ne quitte pas le SDK.
1. Setup : installer et initialiser ChainGate
Choisissez votre gestionnaire de paquets. Le SDK est publié comme un seul paquet npm — installez-le une fois et vous pourrez envoyer Bitcoin, Ethereum et le reste depuis le même import, types inclus :
# pick your package manager
npm install chaingate
pnpm add chaingate
yarn add chaingateRécupérez ensuite une API key gratuite sur le dashboard ChainGate. L'inscription prend une minute et l'offre gratuite suffit pour mener un prototype jusqu'en production. Initialisez le client une fois avec cette key et réutilisez-le pour chaque chaîne :
import { ChainGate } from 'chaingate';
const cg = new ChainGate({ apiKey: process.env.CHAINGATE_API_KEY });Même code sous Node.js et dans le navigateur. Le paquet fonctionne sous Node 22+, dans les navigateurs modernes (Vite, Next.js, Webpack 5+) et sous Bun, sans configuration, donc la même bibliothèque blockchain Node.js que vous importez côté serveur est celle qui tourne dans le navigateur de l'utilisateur. Les primitives crypto comme Buffer et randomBytes sont natives dans le SDK — rien à polyfiller, rien à configurer.
Les types TypeScript sont inclus. Il n'existe pas de paquet @types/chaingate parce qu'il n'en faut pas — chaque classe, méthode et événement public est typé à la source.
2. Envoyer Bitcoin, Litecoin, Dogecoin et Bitcoin Cash
Bitcoin, Litecoin, Dogecoin et Bitcoin Cash partagent le même modèle comptable — les UTXO. Le solde d'un wallet est la somme des sorties non dépensées (unspent transaction outputs) verrouillées sur ses adresses. Pour envoyer des fonds, le wallet sélectionne assez d'UTXO pour couvrir le montant, construit une nouvelle transaction qui les consomme en inputs, envoie au destinataire une sortie, renvoie le reste à lui-même comme sortie de change et paie des frais en satoshis par kilo-octet (ou l'équivalent par chaîne).
ChainGate gère chaque étape — sélection d'UTXO, output de change, palier de frais et signature — derrière un seul appel transfer(). Vous lui donnez une adresse de destination et un montant, il vous renvoie une transaction signée prête à être broadcastée.
Envoyer du Bitcoin depuis Node.js ou le navigateur
Le cas de base. Connectez votre wallet au réseau Bitcoin, créez le transfert, choisissez un palier de frais et faites le 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;
}Pour viser le testnet en développement, remplacez cg.networks.bitcoin par cg.networks.bitcoinTestnet — le reste du code ne bouge pas.
Envoyer du Litecoin depuis Node.js ou le navigateur
Même code, autre réseau. Le diff par rapport au snippet Bitcoin tient littéralement à un identifiant :
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 utilise des adresses SegWit ltc1q… par défaut et confirme un bloc toutes les deux minutes et demie — environ quatre fois plus vite que Bitcoin —, ce qui en fait un choix populaire pour les paiements de faible valeur où la rapidité de règlement compte plus que la profondeur de sécurité.
Envoyer du Dogecoin depuis Node.js ou le navigateur
Même diff, autre chaîne :
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();L'écosystème JavaScript de Dogecoin a pris du retard sur le reste de la famille UTXO. La plupart des forks populaires de bitcoinjs-lib n'ont pas été mis à jour depuis des années et les rares alternatives maintenues sont privées. ChainGate fait partie des très rares options livrant aujourd'hui un support Dogecoin de qualité production en JavaScript.
Envoyer du Bitcoin Cash depuis Node.js ou le navigateur
Bitcoin Cash utilise par défaut les adresses CashAddr, mais le SDK accepte aussi le format legacy — vous pouvez coller l'un comme l'autre dans transfer() et la transaction passera :
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();La validation d'adresse est bidirectionnelle : cg.networks.bitcoincash.isValidAddress() renvoie true pour les deux formats, donc inutile de normaliser la saisie utilisateur avant l'envoi.
Envoyer en UTXO depuis le navigateur
Les quatre snippets UTXO ci-dessus tournent sans modification dans un bundle Vite, Next.js ou Webpack 5 — le même import fonctionne côté client et le même wallet signe localement sans contacter l'API.
Une note de sécurité : ne chargez jamais des clés privées de production directement dans un frontend. Soit la signature reste sur le serveur et seul le broadcast vient du navigateur, soit l'utilisateur fournit la clé via un flow type wallet qu'il maîtrise.
3. Envoyer Ethereum et les chaînes EVM
Le modèle de comptes d'Ethereum est différent — pas d'UTXO, juste une adresse avec un solde et un nonce qui croît de manière monotone. ChainGate masque cette différence derrière le même appel transfer() qu'on a utilisé sur Bitcoin. Les écarts (gestion du nonce, base fee + tip EIP-1559, gas limit) sont calculés pour vous :
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);Envoyer Avalanche depuis Node.js ou dans le navigateur
La C-Chain d'Avalanche est branchée en tant que network de premier rang aux côtés d'Ethereum — même forme d'appel, même wallet, montants en AVAX. Le diff par rapport au snippet Ethereum tient à un seul identifiant :
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();La C-Chain finalise les blocs en deux secondes environ et utilise le même modèle de frais EIP-1559 qu'Ethereum, donc les transferts AVAX se règlent vite et la sortie de recommendedFees() a la même forme. C'est ce qui fait d'Avalanche un choix populaire pour les paiements à haut throughput où le gas Ethereum sortirait l'utilisateur du jeu.
Même wallet, même SDK, toutes les chaînes EVM. Les URLs RPC hébergées couvrent Polygon, Arbitrum, Base, BNB Chain et Sonic d'office ; pour toute autre network EVM — Optimism, Linea, Scroll, Gnosis, votre propre node, un testnet — passez l'URL JSON-RPC directement à evmRpc(). Envoyer du POL sur Polygon, c'est un diff d'une ligne :
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();La gestion du nonce est automatique. Le SDK lit le dernier nonce pending sur le RPC choisi avant de signer, vous n'avez donc pas à le suivre. La construction des frais passe par défaut par l'EIP-1559 (maxFeePerGas + maxPriorityFeePerGas) sur les chaînes qui le supportent et bascule sur le gas pricing legacy sur celles qui ne le font pas.
Le chainId que vous passez à evmRpc() doit être celui que l'endpoint RPC lui-même renvoie, sinon le SDK signera pour le mauvais réseau. La liste des chain ID EVM donne le nombre pour Polygon, Arbitrum, Base, Optimism et 35 autres réseaux et testnets, et montre comment le lire directement depuis n'importe quelle URL RPC.
Si le nœud répond à une diffusion par "nonce too low", "replacement transaction underpriced" ou "insufficient funds for gas * price + value", le guide des erreurs de transaction Ethereum explique ce que signifie chaque message et lesquels coûtent du gas.
Le support du navigateur est identique aux chaînes UTXO. C'est le code qu'on placerait derrière un bouton 'Send' dans une dApp.
4. Estimer les frais avant l'envoi
Affichez toujours les frais avant le broadcast. Les utilisateurs détestent les surprises, les transactions bloquées font perdre du temps et un step 'review and confirm' transforme un flow d'UI à coup unique en quelque chose en quoi l'utilisateur a vraiment confiance.
ChainGate expose la même méthode recommendedFees() sur chaque chaîne — elle renvoie quatre paliers (low, normal, high, maximum) avec les chiffres dont chaque palier a besoin. Sur Bitcoin vous obtenez un taux feePerKbSat et le total estimé en satoshis ; sur Ethereum et les autres chaînes EVM, vous récupérez maxFeePerGas et maxPriorityFeePerGas (EIP-1559) en bigint wei plus une fenêtre estimée de confirmation :
// 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 },
});Le pattern qui marche en production : construire la transaction, appeler recommendedFees(), montrer les quatre paliers à l'utilisateur, le laisser choisir, puis appeler signAndBroadcast(). L'objet transaction reste en mémoire entre l'estimation et le broadcast — pas besoin de le reconstruire.
5. Vérifier le solde avant l'envoi
Une vérification de solde a toute sa place en tête de n'importe quel flow d'envoi. Elle détecte les fautes de frappe, évite de gaspiller du gas pour une transaction qui va échouer et donne à l'utilisateur un chiffre qu'il peut comparer. Chaque chaîne expose le même one-liner — passez une adresse (ou utilisez le wallet connecté) et vous obtenez le solde confirmé et, sur les chaînes qui le supportent, le solde en attente :
// 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`);Combinée à l'estimation de frais, la pre-flight complète tient en trois appels — solde, frais, puis envoi. Branchez tout ça une fois et chaque flow d'envoi de votre app récupère gratuitement la même validation préalable, que vous vérifiiez un solde crypto depuis Node.js côté serveur ou depuis le navigateur.
6. ChainGate vs bitcoinjs-lib, ethers et autres alternatives
ChainGate ne cherche pas à remplacer toutes les bibliothèques bas niveau qui l'ont précédé. Chacune a un rôle clair. Voilà comment se distribuent les compromis quand il faut envoyer des transactions sur plus d'une chaîne :
| Capacité | ChainGate | bitcoinjs-lib | ethers / viem | Implémentation maison |
|---|---|---|---|---|
| Chaînes supportées | BTC, ETH, AVAX+EVM, LTC, DOGE, BCH | Bitcoin uniquement | EVM uniquement | 1 par bibliothèque |
| Lignes pour envoyer du BTC | ~5 | ~40+ | n/a | varie |
| Prêt pour le navigateur | Oui — out of the box | Polyfills requis | Oui | Variable |
| Estimation de frais intégrée | Oui | Non | Partielle | Non |
| Types TypeScript | First-class | Communautaires | Oui | Variable |
Restez sur bitcoinjs-lib ou ethers quand il vous faut un contrôle au byte près sur la transaction, ou que votre app parle à une seule chaîne et que la taille du bundle est le critère décisif. Passez à ChainGate quand vous jonglez avec plusieurs chaînes, êtes pris par une échéance ou pilotez une petite équipe qui ne peut pas se permettre une spécialisation par blockchain.
7. Tarifs et offre gratuite
L'offre gratuite est volontairement généreuse — chaque plan, gratuit compris, embarque le SDK complet : balances, listing d'assets, estimation des frais, signature et broadcast pour toutes les chaînes que nous supportons. Ça suffit pour livrer un prototype, faire tourner un projet perso ou mettre un outil interne en production. Pas de carte bancaire à l'inscription.
Les plans payants relèvent les rate limits et ajoutent du support prioritaire et de la capacité de burst. La montée en gamme se fait en un clic depuis le dashboard.
Voir la page Tarifs pour les chiffres à jour et le chemin d'upgrade.
8. Pour aller plus loin
Vous avez le modèle : un SDK, plusieurs chaînes et la même forme en cinq lignes sur chacune. Pour la suite, la documentation couvre le reste de la surface — signature de messages, transferts ERC-20, transferts de NFT, historique de transactions décodé. Les exemples sur GitHub sont un bon point de départ pour des recettes end-to-end à copier. Et le dashboard de l'API est à un clic dès que vous voulez récupérer une key et déployer quelque chose en prod. Pour creuser la mécanique derrière les frais, le guide compagnon sur le gas Ethereum décrit d'où viennent vraiment les chiffres de recommendedFees(). Le guide sur les hash de transaction explique à quoi ressemble le transactionId renvoyé par signAndBroadcast() sur chaque chaîne et comment le vérifier sur un block explorer.
Questions fréquentes
ChainGate détient-il mes clés privées ?
Puis-je utiliser ChainGate dans le navigateur ?
Oui — chaque exemple de ce guide tourne sans modification dans un bundle Vite, Next.js ou Webpack 5. Le SDK embarque sa propre crypto compatible navigateur, donc il n'y a rien d'extra à installer.
Quels réseaux sont supportés ?
ChainGate offre un support API complet pour Bitcoin, Bitcoin Testnet, Litecoin, Dogecoin, Bitcoin Cash, Ethereum et Avalanche, des endpoints JSON-RPC hébergés pour Polygon, Arbitrum, Base, BNB Chain et Sonic, et le bring-your-own-RPC pour toute autre chaîne EVM — y compris Optimism, Linea, Scroll, Gnosis, des testnets et des nodes auto-hébergés. La matrice complète est dans la documentation.
Puis-je envoyer des transactions de testnet ?
Oui — il n'y a pas de flag testnet spécial. Passez le réseau testnet au même appel cg.connect() qu'en mainnet : pour Bitcoin c'est cg.networks.bitcoinTestnet ; pour un testnet EVM, passez l'URL JSON-RPC et le chain ID du testnet à cg.networks.evmRpc({ rpcUrl, chainId, name, symbol }). Le reste du code est identique aux exemples mainnet de ce guide.
Que se passe-t-il si une transaction échoue ?
Le SDK remonte une erreur typée que vous pouvez attraper et traiter. La plupart des incidents avant broadcast sont rattrapables — l'objet transaction est reconstruit avec un nonce frais ou une nouvelle sélection d'UTXO au retry, donc un second essai passe en général.
ChainGate est-il open source ?
Le SDK JavaScript qui signe et broadcast sur votre machine est publié sur GitHub sous licence MIT — lisez les sources, copiez-le dans votre repo ou forkez-le. L'API ChainGate qui se trouve derrière est un service managé qui s'occupe du reste pour vous. La plupart des équipes utilisent le SDK open source avec l'API hébergée, mais vous pouvez pointer le SDK sur n'importe quelle URL RPC que vous contrôlez si vous préférez héberger votre propre infra.
Pourquoi ChainGate a-t-il besoin d'une clé API ?
Construisez avec ChainGate
Mettez ces idées en pratique — ChainGate fournit wallets, transactions et RPC managé pour Ethereum et plus de 20 autres blockchains en une seule installation.