Как отправлять крипто-транзакции на JavaScript: Bitcoin, Ethereum, Litecoin, Dogecoin и не только — с ChainGate

Практическое руководство на JavaScript по отправке Bitcoin, Ethereum, Avalanche, Litecoin, Dogecoin и Bitcoin Cash из одного SDK — от ChainGate.

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

Чтение on-chain данных из JavaScript всегда было неудобной половиной работы. Получить чистый баланс Bitcoin — подтверждённый и неподтверждённый, как их показывает explorer — обычно означает поднять собственный indexer или биться о шаткий публичный API. Перечислить NFT и токены, которые держит адрес Ethereum или EVM, — это значит склеивать три-четыре endpoint'а explorer'ов, у каждого свой schema, свои rate limit'ы и недостающие поля. А когда дело реально доходит до broadcast'а транзакции, ты снова возвращаешься к bitcoinjs-lib для Bitcoin, ethers или viem для EVM-стороны и полузаброшенному форку под Dogecoin и Litecoin. ChainGate закрывает всё это одним SDK.

ChainGate сворачивает эту работу в один JavaScript SDK. Сделанный как multi-chain SDK для wallet'ов, та же форма вызова отправляет Bitcoin, Ethereum, Avalanche (и любую EVM-цепочку), Litecoin, Dogecoin и Bitcoin Cash, читает балансы адресов и выводит список assets, лежащих на любом адресе. Один и тот же пакет работает в Node.js и в браузере без изменений в коде — каждая crypto-примитива идёт нативно, полифиллы не нужны.

Ниже — базовая отправка в пять строк. Дальше в гайде — тот же паттерн на каждой цепочке плюс оценка fee и проверка баланса перед 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();

Коротко

  • Один SDK, все цепочки. Тот же transfer() покрывает Bitcoin, Ethereum, Avalanche, Litecoin, Dogecoin, Bitcoin Cash и любую EVM-совместимую сеть.
  • Работает без изменений на Node.js 22+ и в современных браузерах — без настройки полифиллов Buffer или crypto.
  • Fee, баланс и broadcast — всё встроено, вторая библиотека не нужна.
  • Подпись всегда происходит локально. Твой private key не покидает SDK.

1. Setup: установка и инициализация ChainGate

Выбери пакетный менеджер. SDK выходит как один пакет npm — установи его один раз, и из того же импорта можно отправить Bitcoin, Ethereum и всё остальное, типы в комплекте:

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

Затем получи бесплатный API key в ChainGate dashboard. Регистрация занимает около минуты, бесплатного tier'а хватает, чтобы выкатить прототип в продакшен. Инициализируй клиент с этим key один раз и переиспользуй его для каждой цепочки:

import { ChainGate } from 'chaingate';

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

Один и тот же код в Node.js и в браузере. Пакет работает на Node 22+, в современных браузерах (Vite, Next.js, Webpack 5+) и в Bun из коробки, так что та же блокчейн-библиотека для Node.js, которую ты импортируешь на сервере, запускается и в браузере пользователя. Crypto-примитивы вроде Buffer и randomBytes идут нативно внутри SDK — нечего полифиллить, нечего настраивать.

Типы TypeScript идут в пакете. Пакета @types/chaingate нет, потому что он не нужен — каждый публичный класс, метод и event типизирован в исходниках.

2. Отправка Bitcoin, Litecoin, Dogecoin и Bitcoin Cash

Bitcoin, Litecoin, Dogecoin и Bitcoin Cash используют одну и ту же бухгалтерскую модель — UTXO. Баланс кошелька — это сумма unspent transaction outputs, привязанных к его адресам. Чтобы отправить средства, кошелёк выбирает достаточное число UTXO под сумму, собирает новую транзакцию, которая использует их как inputs, отправляет получателю один output, возвращает остаток самому себе как change output и платит fee в satoshi за килобайт (или эквивалент по конкретной цепочке).

ChainGate берёт каждый шаг на себя — выбор UTXO, change output, fee tier и подпись — за одним вызовом transfer(). Передаёшь адрес получателя и сумму, получаешь подписанную транзакцию, готовую к broadcast.

Отправка Bitcoin из Node.js или в браузере

Базовый пример. Подключи кошелёк к сети Bitcoin, создай transfer, выбери fee tier и отправь 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;
}

Чтобы попасть в testnet на разработке, поменяй cg.networks.bitcoin на cg.networks.bitcoinTestnet — остальной код тот же.

Отправка Litecoin из Node.js или в браузере

Тот же код, другая сеть. Diff против Bitcoin-сниппета — буквально один идентификатор:

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 по умолчанию использует SegWit-адреса ltc1q… и подтверждает блоки каждые две с половиной минуты — примерно в четыре раза быстрее Bitcoin —, что делает его популярным для платежей малой стоимости, где скорость settlement'а важнее глубины безопасности.

Отправка Dogecoin из Node.js или в браузере

Тот же diff, другая цепочка:

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();

JavaScript-экосистема Dogecoin отстала от остальной UTXO-семьи. Большинство популярных форков bitcoinjs-lib не обновлялись годами, а немногие поддерживаемые альтернативы — приватные. ChainGate — одна из очень немногих опций сегодня с production-ready поддержкой Dogecoin на JavaScript.

Отправка Bitcoin Cash из Node.js или в браузере

Bitcoin Cash по умолчанию использует CashAddr, но SDK принимает и legacy-формат — можно вставить любой из них в transfer(), и сеть всё равно подтвердит транзакцию:

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();

Валидация адреса двусторонняя: cg.networks.bitcoincash.isValidAddress() возвращает true для обоих форматов, поэтому нормализовать пользовательский ввод перед отправкой не нужно.

UTXO-отправки из браузера

Все четыре UTXO-сниппета выше работают без изменений в bundle Vite, Next.js или Webpack 5 — тот же import работает на клиенте, и тот же кошелёк подписывает локально, не трогая API.

Заметка о безопасности: никогда не загружай продакшен private keys прямо во фронтенд. Либо держи подпись на сервере и шли из браузера только broadcast, либо пусть пользователь подаёт ключ через wallet-flow, который контролирует он сам.

3. Отправка Ethereum и EVM-цепочек

Аккаунт-модель Ethereum другая — никаких UTXO, только адрес с балансом и монотонно растущим nonce. ChainGate прячет эту разницу за тем же transfer(), которым ты пользовался на Bitcoin. Различия (управление nonce, base fee + tip EIP-1559, gas limit) считаются за тебя:

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);

Отправка Avalanche из Node.js или браузера

C-Chain Avalanche подключён как сеть первого класса рядом с Ethereum — та же форма вызова, тот же кошелёк, суммы в AVAX. Diff относительно Ethereum-сниппета — один идентификатор:

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();

C-Chain финализирует блоки примерно за две секунды и работает на той же модели fee EIP-1559, что и Ethereum, поэтому переводы AVAX подтверждаются быстро, а выход recommendedFees() имеет ту же форму. Именно это делает Avalanche популярным выбором для высокообъёмных платежей, где ethereum-gas вытеснил бы пользователя по цене.

Тот же кошелёк, тот же SDK, любая EVM-цепочка. Hosted RPC URL'ы покрывают Polygon, Arbitrum, Base, BNB Chain и Sonic из коробки; для любой другой EVM-сети — Optimism, Linea, Scroll, Gnosis, твой собственный node, testnet — передай JSON-RPC URL прямо в evmRpc(). Отправить POL в Polygon — diff в одну строку:

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();

Управление nonce автоматическое. SDK перед подписью читает последний pending nonce из выбранного RPC, поэтому отслеживать его самому не нужно. Конструирование fee по умолчанию идёт через EIP-1559 (maxFeePerGas + maxPriorityFeePerGas) на цепочках, которые это поддерживают, и откатывается на legacy gas pricing на остальных.

chainId, который ты передаёшь в evmRpc(), должен совпадать с тем, что сообщает сам RPC-эндпоинт, иначе SDK подпишет транзакцию для другой сети. В списке chain ID EVM-сетей есть номер для Polygon, Arbitrum, Base, Optimism и ещё 35 сетей и тестнетов, а также показано, как прочитать его напрямую с любого RPC URL.

Если узел отвечает на broadcast ошибкой «nonce too low», «replacement transaction underpriced» или «insufficient funds for gas * price + value», руководство по ошибкам транзакций Ethereum объясняет, что значит каждое сообщение и какие из них стоят gas.

Поддержка браузера такая же, как для UTXO-цепочек. Это тот код, который ты бы поставил за кнопкой 'Send' в dApp.

4. Оценка fee перед отправкой

Всегда показывай fee перед broadcast'ом. Пользователи не любят сюрпризов, застрявшие транзакции крадут время, а шаг 'review and confirm' превращает одноразовый UI-flow в то, чему пользователь действительно доверяет.

ChainGate выставляет тот же метод recommendedFees() на каждой цепочке — он возвращает четыре tier'а (low, normal, high, maximum) с теми числами, которые нужны каждому tier'у. На Bitcoin ты получаешь ставку feePerKbSat и оценочный итог в satoshi; на Ethereum и других EVM-цепочках — EIP-1559 maxFeePerGas и maxPriorityFeePerGas как bigint в wei плюс оценочное окно подтверждения:

// 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 },
});

Паттерн, работающий в продакшене: построил транзакцию, вызвал recommendedFees(), показал четыре tier'а пользователю, дал выбрать, потом вызвал signAndBroadcast(). Объект транзакции остаётся в памяти между оценкой и broadcast'ом — пересобирать ничего не нужно.

5. Проверка баланса перед отправкой

Проверка баланса должна стоять в самом начале любого send-flow. Она ловит опечатки, не даёт сжечь gas на заранее провальную транзакцию и даёт пользователю число, которое он может проверить глазом. Каждая цепочка выставляет один и тот же one-liner — передаёшь адрес (или используешь подключённый кошелёк) и получаешь подтверждённый баланс, а на цепочках, которые это поддерживают, — неподтверждённую часть:

// 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`);

Вместе с оценкой fee полный pre-flight — это три вызова: баланс, fee, потом отправка. Соедини это один раз, и каждый send-flow в твоём приложении бесплатно получает ту же предварительную валидацию — проверяешь ли ты крипто баланс из Node.js на сервере или из браузера.

6. ChainGate vs bitcoinjs-lib, ethers и другие альтернативы

ChainGate не пытается заменить каждую низкоуровневую библиотеку, появившуюся раньше. У каждой из них своя чёткая задача. Вот как раскладываются trade-off'ы, когда нужно отправлять транзакции в больше чем одной цепочке:

ВозможностьChainGatebitcoinjs-libethers / viemСвоя реализация
Поддерживаемые цепочкиBTC, ETH, AVAX+EVM, LTC, DOGE, BCHТолько BitcoinТолько EVM1 на библиотеку
Строк, чтобы отправить BTC~5~40+не применимопо-разному
Готовность к браузеруДа — из коробкиНужны полифиллыДаПо-разному
Встроенная оценка feeДаНетЧастичноНет
Типы TypeScriptFirst-classСообществоДаПо-разному

Оставайся на bitcoinjs-lib или ethers, когда тебе нужен побайтовый контроль над формой транзакции или твоё приложение работает с одной цепочкой и размер bundle'а — решающий фактор. Переходи на ChainGate, когда жонглируешь несколькими цепочками сразу, гонишься за дедлайном или ведёшь маленькую команду, которая не может позволить себе специализацию по блокчейнам.

7. Тарифы и бесплатный tier

Бесплатный tier — щедрый намеренно: каждый план, включая бесплатный, идёт с полным SDK — балансы, перечни assets, оценка fee, подпись и broadcast по каждой поддерживаемой цепочке. Этого хватит, чтобы выкатить прототип, тащить личный проект или вывести внутренний инструмент в продакшен. На регистрации не просят карту.

Платные tier'ы поднимают rate limit'ы и добавляют priority support и burst-капасити. Апгрейд — клик внутри dashboard.

Актуальные числа и путь апгрейда — на странице тарифов.

8. Куда двигаться дальше

Ты получил модель: один SDK, несколько цепочек и одна и та же форма из пяти строк на каждой. Дальше — документация закрывает остальную поверхность: подпись сообщений, ERC-20-переводы, перемещения NFT, decoded история транзакций. Примеры на GitHub — хорошая отправная точка с end-to-end рецептами, которые можно скопировать. А API dashboard в одном клике, когда захочешь забрать key и выкатить что-то в прод. Чтобы поглубже понять механику за fee, спутник этого гайда про Ethereum gas разбирает, откуда на самом деле берутся числа в recommendedFees(). Руководство по хешам транзакций объясняет, как выглядит transactionId, который возвращает signAndBroadcast(), в каждой сети и как проверить его в explorer'е.

Частые вопросы

Хранит ли ChainGate мои private keys?
Нет. Создание кошелька, derivation ключей и подпись выполняются локально на твоём устройстве. ChainGate API обрабатывает только запросы на чтение и broadcast уже подписанных raw-транзакций — твоя seed phrase и private key не покидают SDK.
Можно ли использовать ChainGate в браузере?

Да — каждый пример из этого гайда работает без изменений в bundle Vite, Next.js или Webpack 5. SDK включает собственную браузерную crypto, поэтому ничего дополнительно ставить не нужно.

Какие сети поддерживаются?

ChainGate даёт полную API-поддержку для Bitcoin, Bitcoin Testnet, Litecoin, Dogecoin, Bitcoin Cash, Ethereum и Avalanche, hosted JSON-RPC endpoints для Polygon, Arbitrum, Base, BNB Chain и Sonic, а также bring-your-own-RPC для любой другой EVM-цепочки — включая Optimism, Linea, Scroll, Gnosis, testnet'ы и self-hosted node'ы. Полная матрица — в документации.

Можно ли отправлять testnet-транзакции?

Да — никакого специального флага testnet нет. Передай testnet-сеть в тот же cg.connect(), что и на mainnet: для Bitcoin это cg.networks.bitcoinTestnet; для EVM-testnet'а передай его JSON-RPC URL и chain ID в cg.networks.evmRpc({ rpcUrl, chainId, name, symbol }). Остальной код идентичен mainnet-примерам в этом гайде.

Что будет, если транзакция не пройдёт?

SDK выдаёт типизированную ошибку, которую можно поймать и обработать. Большинство проблем до broadcast'а восстановимы — объект транзакции при повторе пересобирается со свежим nonce или новой выборкой UTXO, поэтому вторая попытка обычно проходит.

ChainGate — open source?

JavaScript SDK, который подписывает и broadcast'ит на твоей машине, опубликован на GitHub под лицензией MIT — читай исходники, vendor'ь, форкай. ChainGate API за ним — managed-сервис, который берёт остальное на себя. Большинство команд использует open-source SDK с hosted API, но если хочешь хостить инфраструктуру сам, SDK можно направить на любой RPC URL, который ты контролируешь.

Зачем ChainGate нужен API key?
API key аутентифицирует вызовы к бэкенду ChainGate — а именно бэкенд закрывает то, что SDK не может сделать сам: обрабатывает JSON-RPC-запросы к нужной цепочке, читает UTXO и балансы и broadcast'ит подписанные транзакции. Подпись по-прежнему происходит локально твоим кошельком; ключ авторизует только трафик чтения и broadcast, который проходит через инфраструктуру ChainGate. На бесплатном тарифе key выдаётся в дашборде без банковской карты.

Создавай с ChainGate

Превращай идеи в код — ChainGate даёт кошельки, транзакции и управляемый RPC для Ethereum и 20+ блокчейнов в одной библиотеке.