JavaScript で暗号資産トランザクションを送る方法:ChainGate で扱う Bitcoin、Ethereum、Litecoin、Dogecoin、その他のチェーン

1 つの SDK で JavaScript から Bitcoin、Ethereum、Avalanche、Litecoin、Dogecoin、Bitcoin Cash を送るための実践ガイド —— ChainGate.

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

JavaScript からオンチェーンデータを読むのは、これまでずっと厄介な仕事でした。Bitcoin の残高をきれいに取得する(エクスプローラと同じように確認済みと未確認の両方)には、たいてい自前の indexer を立てるか、不安定な公開 API に叩き続けることになります。Ethereum や EVM のアドレスが保有する NFT やトークンを一覧するには、それぞれ独自のスキーマ、レートリミット、欠けているフィールドを持つエクスプローラのエンドポイントを 3 つ 4 つ縫い合わせる必要があります。そしていざトランザクションを broadcast したくなれば、Bitcoin には bitcoinjs-lib、EVM 側には ethers か viem、Dogecoin と Litecoin には半ば放置されたフォーク、という元の場所に戻ってしまいます。ChainGate はそのすべてを 1 つの SDK でカバーします。

ChainGate はその仕事を 1 つの JavaScript SDK に畳み込みます。マルチチェーンウォレット SDK として作られているので、同じ呼び出し形で Bitcoin、Ethereum、Avalanche(およびすべての EVM チェーン)、Litecoin、Dogecoin、Bitcoin Cash を送信し、アドレスの残高を読み、任意のアドレスにある assets を一覧します。同じパッケージが Node.js でもブラウザでも、コードを変えずに動きます —— あらゆる暗号プリミティブはネイティブで同梱され、polyfill は不要です。

以下が基本となる 5 行の送信コードです。本ガイドの残りでは同じパターンを各チェーンでなぞりつつ、broadcast の前に fee 見積もりと残高チェックを重ねていきます:

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

要約

  • 1 つの SDK で、すべてのチェーン。 同じ transfer() API が Bitcoin、Ethereum、Avalanche、Litecoin、Dogecoin、Bitcoin Cash、そしてすべての EVM 互換ネットワークをカバーします。
  • Node.js 22+ と最新ブラウザで変更なしに動作 —— Buffer や crypto の polyfill 設定は不要です。
  • fee、残高、broadcast はすべて組み込み済み —— どれにも 2 つ目のライブラリは要りません。
  • 署名は常にローカルで行われます。あなたの private key は SDK の外に出ません。

1. セットアップ:ChainGate のインストールと初期化

パッケージマネージャを選んでください。SDK は型まで含めて 1 つの npm パッケージとして公開されており —— 一度インストールすれば、同じ import から Bitcoin、Ethereum やその他を送信できます:

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

次に、ChainGate ダッシュボード で無料の API key を取得します。登録は約 1 分で済み、無料 tier はプロトタイプを本番に上げるのに十分です。その key で client を一度初期化し、すべてのチェーンで使い回します:

import { ChainGate } from 'chaingate';

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

Node.js でもブラウザでも同じコード。 パッケージは Node 22+、最新ブラウザ(Vite、Next.js、Webpack 5+)、Bun でそのまま動きます。サーバー側で import するその Node.js ブロックチェーンライブラリが、そのままユーザーのブラウザでも動きます。Buffer や randomBytes のような暗号プリミティブは SDK にネイティブで同梱されており —— polyfill するものも、設定するものもありません。

TypeScript の型はパッケージに同梱。 @types/chaingate パッケージは存在しません。必要ないからです —— 公開されているクラス、メソッド、イベントはすべてソース時点で完全に型付けされています。

2. Bitcoin、Litecoin、Dogecoin、Bitcoin Cash を送る

Bitcoin、Litecoin、Dogecoin、Bitcoin Cash は同じ会計モデル —— UTXO を共有しています。ウォレットの残高は、そのアドレスにロックされた unspent transaction outputs の合計です。送金時、ウォレットは金額を賄うのに十分な UTXO を選び、それらを input として消費する新しいトランザクションを組み立て、受取人へ 1 つの output を送り、お釣りを change output として自分自身に戻し、キロバイトあたりの satoshi(またはチェーンごとの相当値)で fee を支払います。

ChainGate はこのすべて —— UTXO 選択、change output、fee tier、署名 —— を transfer() という 1 回の呼び出しの裏で処理します。送信先アドレスと金額を渡すと、broadcast の準備が整った署名済みトランザクションが返ってきます。

Node.js とブラウザで Bitcoin を送る

基本例。ウォレットを 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 に置き換えるだけで済みます —— 残りのコードはそのままです。

Node.js とブラウザで Litecoin を送る

コードは同じ、ネットワークが違う。Bitcoin スニペットとの diff は文字どおり 1 つの識別子だけです:

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 はデフォルトで ltc1q… 形式の SegWit アドレスを使い、ブロックを 2 分半ごとに承認します —— Bitcoin の約 4 倍の速さです —— セキュリティの厚みより settlement の速さが効く小額決済で人気の選択肢です。

Node.js とブラウザで Dogecoin を送る

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

Dogecoin の JavaScript エコシステムは UTXO ファミリーの中で取り残されてきました。bitcoinjs-lib の人気フォークの多くは何年も更新されておらず、メンテされている代替手段の多くはプライベートです。ChainGate は今日、JavaScript で本番品質の Dogecoin サポートを提供する数少ない選択肢の 1 つです。

Node.js とブラウザで Bitcoin Cash を送る

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 を送る

上記 4 つの UTXO スニペットは、Vite、Next.js、Webpack 5 のいずれの bundle でもそのまま動きます —— 同じ import がクライアント側で動き、同じウォレットが API に問い合わせず、ローカルで署名します。

セキュリティ上の注意:本番用の private key を直接フロントエンドに読み込むことは絶対に避けてください。署名はサーバー側に置き、ブラウザからは broadcast だけを行うか、ユーザー自身が制御する wallet 風のフローからキーを供給してもらうかのどちらかです。

3. Ethereum と EVM チェーンを送る

Ethereum のアカウントモデルは別物です —— UTXO はなく、残高と単調増加する nonce を持ったアドレスがあるだけです。ChainGate はこの違いを、Bitcoin で使ったのと同じ transfer() の裏に隠します。差分(nonce 管理、EIP-1559 の base fee + tip、gas limit)は ChainGate が計算します:

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 やブラウザから送る

Avalanche の C-Chain は Ethereum と並んでファーストクラスのネットワークとして組み込まれています —— 同じ呼び出し形、同じウォレット、AVAX 建ての金額です。Ethereum スニペットとの diff は識別子 1 つだけ:

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 はおよそ 2 秒でブロックをファイナライズし、Ethereum と同じ EIP-1559 fee モデルで動くため、AVAX 送金はすばやく確定し、recommendedFees() の出力も同じ形になります。これが Ethereum gas ではコストが合わなくなるような高スループット決済で、Avalanche がよく選ばれる理由です。

同じウォレット、同じ SDK、すべての EVM チェーン。ホスト型 RPC URL は Polygon、Arbitrum、Base、BNB Chain、Sonic を箱から出してすぐカバーします。それ以外の EVM ネットワーク —— Optimism、Linea、Scroll、Gnosis、自前の node、testnet —— は JSON-RPC URL を直接 evmRpc() に渡してください。Polygon で POL を送るのは 1 行の 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 は署名前に選択した RPC から最新の pending nonce を読み取るため、自分で追いかける必要はありません。fee 構築は対応チェーンでは EIP-1559(maxFeePerGas + maxPriorityFeePerGas)を既定とし、対応していないチェーンでは legacy gas pricing にフォールバックします。

evmRpc() に渡す chainId は、その RPC エンドポイント自身が返す値でなければなりません。違っていれば SDK は別のネットワーク向けに署名してしまいます。EVM チェーンID一覧には Polygon、Arbitrum、Base、Optimism と、その他 35 のネットワークとテストネットの番号が載っており、任意の RPC URL から直接読み取る方法も示しています。

ブロードキャストに対してノードが「nonce too low」「replacement transaction underpriced」「insufficient funds for gas * price + value」と答えてきたら、Ethereum の取引エラーのガイドが各メッセージの意味と、どれが gas を消費するのかを説明しています。

ブラウザサポートは UTXO チェーンと同等です。これがそのまま、dApp の 'Send' ボタンの裏に置くコードになります。

4. 送信前の fee 見積もり

broadcast の前に必ず fee を見せましょう。ユーザーはサプライズを嫌い、詰まったトランザクションは時間を奪い、'review and confirm' のステップは一発勝負の UI フローを、ユーザーが本当に信頼できるものに変えます。

ChainGate は各チェーンで同じ recommendedFees() メソッドを公開します —— 4 つの tier(low、normal、high、maximum)と、それぞれに必要な数値を返します。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() を呼び、4 つの tier をユーザーに見せて選んでもらい、それから signAndBroadcast() を呼ぶ。トランザクションオブジェクトは見積もりと broadcast の間ずっとメモリに残ります —— 再構築は不要です。

5. 送信前の残高チェック

残高チェックはあらゆる送信フローの先頭に置くべきです。タイポを捕まえ、失敗するトランザクションに gas を浪費するのを防ぎ、ユーザーに照合できる数字を提供します。各チェーンが同じワンライナーを公開していて、アドレスを渡す(または接続済みウォレットを使う)だけで、確認済み残高と、対応チェーンでは未確認との内訳が手に入ります:

// 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 は 3 回の呼び出しで済みます —— 残高、fee、そして送信。一度配線してしまえば、アプリ内のすべての送信フローが同じ事前検証を無料で享受できます。サーバーの Node.js から暗号資産の残高を確認するときも、ブラウザから確認するときも、同じです。

6. ChainGate と bitcoinjs-lib、ethers、その他の選択肢

ChainGate は、それ以前のすべての低レベルライブラリを置き換えようとしているわけではありません。それぞれに明確な役割があります。複数のチェーンに送信が必要なときの trade-off は次のようになります:

機能ChainGatebitcoinjs-libethers / viem自前実装
対応チェーンBTC、ETH、AVAX+EVM、LTC、DOGE、BCHBitcoin のみEVM のみライブラリにつき 1
BTC を送る行数~5~40+該当なしまちまち
ブラウザ対応はい —— 箱から出してすぐpolyfill が必要はいまちまち
fee 見積もり内蔵はいいいえ部分的いいえ
TypeScript 型First-classコミュニティはいまちまち

トランザクションの形式をバイト単位で制御したいとき、あるいはアプリが 1 つのチェーンだけを相手にしていて bundle サイズが決め手になるときは、bitcoinjs-lib や ethers を使い続けるのが正解です。複数チェーンを同時にさばいているとき、deadline に追われているとき、ブロックチェーンごとに専門化する余裕がない小規模チームを率いているときは、ChainGate に乗り換える価値があります。

7. 料金プランと無料 tier

無料 tier は意図的に寛大です —— 無料を含むすべてのプランに、サポートしている全チェーン分の SDK 一式(残高、assets の一覧、fee 見積もり、署名、broadcast)が付いてきます。プロトタイプの公開、個人プロジェクトの運用、社内ツールを本番に乗せるには十分です。サインアップにクレジットカードは不要です。

有料 tier は rate limit を引き上げ、優先サポートと burst キャパシティを追加します。アップグレードはダッシュボードからワンクリックです。

最新の数値とアップグレードの導線は 料金ページ を参照してください。

8. 次に進む先

モデルは手に入りました。1 つの SDK、複数のチェーン、それぞれで同じ 5 行の形。ここからは、ドキュメント が残りの面 —— メッセージ署名、ERC-20 転送、NFT 移動、デコード済みのトランザクション履歴 —— をカバーします。GitHub のサンプル はコピーして使えるエンドツーエンドのレシピの良い出発点です。そして API ダッシュボード は、key を取得して何かを公開したくなったときワンクリックの距離です。fee の裏側のメカニクスをもっと深掘りしたい人は、姉妹編の Ethereum gas で recommendedFees() の数値が実際にどこから来ているのかを解きほぐしています。また、トランザクションハッシュのガイドでは、signAndBroadcast() が返す transactionId が各チェーンでどのような形をしているか、ブロックエクスプローラーでどう確認するかを説明しています。

よくある質問

ChainGate は私の private key を保持しますか?
いいえ。ウォレット作成、key の derivation、署名はすべてあなたのデバイス上でローカルに実行されます。ChainGate API は読み取り系の呼び出しと、署名済みの raw トランザクションの broadcast を扱うだけで、あなたの seed phrase と private key は SDK の外に出ません。
ChainGate はブラウザで使えますか?

はい —— 本ガイドの全サンプルは Vite、Next.js、Webpack 5 のいずれの bundle でもそのまま動きます。SDK はブラウザ互換の crypto を同梱しているので、追加でインストールするものはありません。

対応しているネットワークは?

ChainGate は Bitcoin、Bitcoin Testnet、Litecoin、Dogecoin、Bitcoin Cash、Ethereum、Avalanche に対する API フルサポートを、Polygon、Arbitrum、Base、BNB Chain、Sonic に対するホスト型 JSON-RPC エンドポイントを、その他すべての EVM チェーンに対する bring-your-own-RPC を提供します —— Optimism、Linea、Scroll、Gnosis、各種 testnet、自前の node を含みます。完全なマトリクスはドキュメントにあります。

testnet トランザクションも送れますか?

はい —— testnet 用の特別なフラグはありません。mainnet と同じ cg.connect() に testnet のネットワークを渡すだけです。Bitcoin では cg.networks.bitcoinTestnet です。EVM の testnet では、その JSON-RPC URL と chain ID を cg.networks.evmRpc({ rpcUrl, chainId, name, symbol }) に渡してください。残りのコードは本ガイドの mainnet サンプルとまったく同じです。

トランザクションが失敗したらどうなりますか?

SDK は捕捉して扱える型付きエラーを返します。broadcast 前の問題は大半が回復可能で、リトライ時にはトランザクションオブジェクトが新しい nonce と新しい UTXO 選択で再構築されるため、2 回目の試行はたいてい通ります。

ChainGate はオープンソースですか?

あなたのマシンで署名と broadcast を行う JavaScript SDK は MIT ライセンスの下で GitHub に公開されています —— ソースを読むのも、vendor するのも、フォークするのも自由です。その背後にある ChainGate API は、残りをすべて引き受けるマネージドサービスです。多くのチームはオープンソースの SDK とホスト型 API を組み合わせて使いますが、自前のインフラを運用したい場合は、SDK を自分が制御する任意の RPC URL に向けることもできます。

なぜ ChainGate は API key が必要なのですか?
API key は ChainGate のバックエンドへの呼び出しを認証します。バックエンドが担うのは、SDK だけではできない部分——使っているチェーンへの JSON-RPC リクエストの処理、UTXO と残高の取得、署名済みトランザクションの broadcast です。署名はあくまでローカルでウォレットを使って行われます。key は ChainGate のインフラを通る読み取りと broadcast のトラフィックを許可するだけです。無料プランではダッシュボードからクレジットカードなしで key を発行できます。

ChainGate で構築する

アイデアをコードに落とし込みましょう — ChainGate は Ethereum と 20 以上のブロックチェーン向けのウォレット、トランザクション、マネージド RPC を 1 つのライブラリで提供します。