はじめに
Ethereumのスマートコントラクトを呼び出したい、ウォレットのアドレスから残高を確認したい——そう思って公式ドキュメントを開くと、JSON-RPCの仕様やABI(Application Binary Interface)のエンコード規則が並んでいて、何から手をつければいいのか分からなくなった経験はないでしょうか。生のRPC呼び出しを自前で書くのは、思った以上に骨が折れる作業です。
Web3.js は、そうした低レベルなやり取りを吸収してくれるEthereum向けのJavaScript APIです。単位変換やアドレスの正規化、署名や検証、ABIのエンコード/デコードといった処理を、シンプルなメソッド呼び出しに置き換えてくれます。
ここで一度、サンプルへの導線を置きます。ネットワーク接続なしでその場で動かせるサンプルを用意したので、先に挙動を見たい方はこちらからどうぞ。
Web3.jsとは
Web3.jsは、Ethereumノードとブラウザ・Node.jsアプリケーションをつなぐJavaScriptライブラリです。もともとEthereum Foundationが中心となって開発していましたが、現在はChainSafeがメンテナンスを引き継ぎ、v4系として活発に開発が続けられています。v4では内部実装がTypeScriptで全面的に書き直され、web3-utilsやweb3-eth-accountsといった機能ごとのサブパッケージに分割されました。
主な特徴
- TypeScriptネイティブ - v4以降はTypeScriptでゼロから書き直されており、型定義が標準で付属します
- モジュール分割設計 -
web3.utils、web3.eth.accounts、web3.eth.abiなど機能ごとに分かれているため、必要な部分だけを使えます - プラガブルなプロバイダ - HTTP、WebSocket、IPCなど接続方式を切り替えられ、MetaMaskのようなブラウザウォレットとも連携できます
- ローカルで完結する暗号処理 - アカウント生成や署名、ABIエンコードはRPC通信なしでブラウザ内だけで実行できます
インストール
npm install web3
Yarnを使っている場合は次のコマンドです。
yarn add web3
Web3.jsのサンプルを動かす
Web3.jsにはブロックチェーンへの接続なしでも使えるweb3.utilsという便利なユーティリティ群があります。ここではtoWei / fromWeiによるEtherとWei(Ethereumの最小単位)の変換と、toChecksumAddressによるアドレスの正規化を試せるようにしました。入力欄の数値やアドレスを書き換えると、その場で結果が変わります。
要点だけを抜き出すと、次のようなコードです。
import { Web3 } from 'web3'
const web3 = new Web3()
// EtherをWeiに変換(1 Ether = 10^18 Wei)
web3.utils.toWei('1.5', 'ether') // '1500000000000000000'
// WeiをEtherに変換
web3.utils.fromWei('1500000000000000000', 'ether') // '1.5'
// アドレスをEIP-55のチェックサム形式に変換
web3.utils.toChecksumAddress('0x742d35cc6634c0532925a3b844bc9e7595f0beb')
実際に動かせるものが下です。金額欄やアドレス欄を空にしたり、桁の多い数値を入れたりして挙動を確かめてみてください。
toWeiは指定した単位(ether、gweiなど)を最小単位のWeiに変換し、fromWeiはその逆を行います。toChecksumAddressは小文字だけのアドレスを渡すと、大文字小文字を混在させたEIP-55形式に変換します。アドレスの一部を書き換えて崩すと、web3.utils.toChecksumAddressが例外を投げることも確認できます。
基本的な使い方
Web3.jsを使う最初の一歩は、Web3インスタンスを作ることです。RPCノードのURLを渡せばネットワークに接続できますが、ユーティリティ関数だけを使う場合はプロバイダなしでもインスタンス化できます。
import { Web3 } from 'web3'
// プロバイダを指定して接続する場合
const web3 = new Web3('https://ethereum-rpc.publicnode.com')
// ブロック番号を取得する例(ネットワーク通信が発生します)
const blockNumber = await web3.eth.getBlockNumber()
console.log(blockNumber)
ネットワーク接続を伴う処理は環境やRPCの状態に依存するため、ここでは動かせるサンプルとして提示していません。実際に試す際は、InfuraやAlchemyなどのRPCプロバイダのエンドポイントを用意してください。
実践的なユースケース
アカウントの生成と署名・検証
DAppを開発していると、ウォレットを持たないテスト用アカウントを作りたい場面や、メッセージに署名してその真正性を検証したい場面が出てきます。Web3.jsのweb3.eth.accounts.create()は秘密鍵と公開アドレスのペアをその場で生成し、accounts.sign() / accounts.recover()で署名と検証ができます。いずれもネットワーク通信なしでブラウザ内だけで完結する処理です。
import { Web3 } from 'web3'
const web3 = new Web3()
// アカウント(秘密鍵とアドレス)を生成
const account = web3.eth.accounts.create()
// メッセージに署名
const signed = web3.eth.accounts.sign('hello web3.js', account.privateKey)
// 署名からアドレスを復元して検証
const recovered = web3.eth.accounts.recover('hello web3.js', signed.signature)
console.log(recovered === account.address) // true
「新しいアカウントを生成」を押すたびにweb3.eth.accounts.create()が別のアドレスと秘密鍵のペアを作ります。メッセージ欄を書き換えると、その内容で再署名・再検証が走り、常に自分のアドレスと一致することが確認できます。
スマートコントラクトのABIエンコード/デコード
スマートコントラクトの関数を呼び出すには、関数名と引数をEthereumが理解できるバイナリ形式(ABIエンコード)に変換する必要があります。web3.eth.abi.encodeParameters()とdecodeParameters()を使えば、この変換をローカルで行えます。
import { Web3 } from 'web3'
const web3 = new Web3()
// uint256とstringをABIエンコード
const encoded = web3.eth.abi.encodeParameters(
['uint256', 'string'],
[123, 'hello']
)
// エンコードしたデータを元の型にデコード
const decoded = web3.eth.abi.decodeParameters(
['uint256', 'string'],
encoded
)
encodeParametersは型名の配列と値の配列を受け取り、Ethereumのコントラクトが解釈できる16進文字列を返します。decodeParametersは同じ型指定でその逆変換を行い、元の値に戻せることが確認できます。実際のコントラクト呼び出しでは、この結果をeth_callやeth_sendTransactionのdataフィールドに渡します。
トランザクションのオフライン署名
秘密鍵をノードに送らずにトランザクションへ署名したい場合、web3.eth.accounts.signTransaction()を使えばローカルで署名だけを完結できます。署名済みのデータは後からsendSignedTransactionでブロードキャストする、という2段階の運用が可能です。
import { Web3 } from 'web3'
const web3 = new Web3()
const account = web3.eth.accounts.create()
const tx = {
to: '0x0000000000000000000000000000000000dEaD',
value: web3.utils.toWei('0.01', 'ether'),
gas: 21000,
gasPrice: await web3.eth.getGasPrice(), // ネットワーク接続時のみ
nonce: 0,
chainId: 1,
}
const signed = await web3.eth.accounts.signTransaction(tx, account.privateKey)
console.log(signed.rawTransaction)
signTransactionは秘密鍵を外部に送信せず、ブラウザ内だけで署名済みのRLPエンコードデータ(rawTransaction)を生成します。宛先や送金額を書き換えると署名結果も変わり、このrawTransactionをそのままRPCノードに送ればブロードキャストできる、という仕組みが体感できます。
まとめ
Web3.jsは、Ethereumの複雑なJSON-RPCやABIエンコードの規則を意識せずに、単位変換・アドレス操作・署名・コントラクト呼び出しをシンプルなAPIとして扱えるライブラリです。v4以降はTypeScriptで全面的に書き直され、ChainSafeのもとで開発が継続されています。
今回紹介したweb3.utilsやweb3.eth.accounts、web3.eth.abiはネットワーク接続なしでも試せる部分なので、まずはローカルで挙動をつかんでから、実際のRPCプロバイダに接続してコントラクト呼び出しやトランザクション送信に進んでみてください。
