Neutrinoで働くブロックチェーンエンジニアのブログ

渋谷の専門特化コワークNeutrinoに入居してブロックチェーン領域のエンジニアとして働いています。(Neutrino運営企業とは直接関係ありません)

ethers.jsでBIP39のニーモニックフレーズとBIP44準拠のHDWalletを使う

ethers.jsが最近人気とのことで使ってみます。ethers.jsはweb3.jsに近しい、node.jsでethereumを用いることができるライブラリです。みた感じ、web3.jsにはbip39のニーモニックフレーズ(文字列から秘密鍵を作成する機能)が見当たりませんでしたが、ethers.jsでは簡単に作れました。

予備知識となるBIP39、BIP44の話はこちらに丁寧な説明があるためご参照ください。

www.jpbitcoinblog.info

バージョン

node.js v10.16.3
npm 6.10.3
ethers.js 4.0.45

ethers.jsの特徴

公式のFeaturesには以下のように書いています。 What is ethers.js — ethers.js 4.0.0 documentation

  • 秘密キーをクライアントサイドに安全かつ確実に保管する
  • JSONウォレットのインポートとエクスポート(Geth、Parity、crowdsale)
  • BIP39ニーモニックフレーズ(12ワードのバックアップフレーズ)およびHDウォレット(英語、イタリア語、日本語、韓国語、簡体字中国語、繁体字中国語 etc)のインポートとエクスポート
  • ABIv2やHuman-Readable ABIなど、任意のコントラクトABIからJavaScriptオブジェクトを作成する
  • JSON-RPC、INFURA、Etherscan、またはMetaMaskを介してEthereumノードに接続する
  • Ethereum Name Service(ENS)の名前解決(ENS はこちら参照 https://note.com/akira_19/n/na1459f4c83e8?magazine_key=md88688a3936b )
  • 小さなサイズ(圧縮で~88kb;非圧縮で284kb)
  • Ethereum機能に対応する包括的な機能
  • 広範なドキュメント
  • 広範なテストケース
  • 完全なTypeScript対応
  • MITライセンス(全ての依存関係を含む)で自由に使える完全なオープンソースである

今回は「BIP39ニーモニックフレーズ(12ワードのバックアップフレーズ)およびHDウォレット(英語、イタリア語、日本語、韓国語、簡体字中国語、繁体字中国語 etc)のインポートとエクスポート」に焦点をあてます。

ethers.jsのインストール

npm install ethers

$ npm install ethers
npm WARN saveError ENOENT: no such file or directory, open '/Users/nao/experiments/ethersjs/package.json'
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN enoent ENOENT: no such file or directory, open '/Users/nao/experiments/ethersjs/package.json'
npm WARN ethersjs No description
npm WARN ethersjs No repository field.
npm WARN ethersjs No README data
npm WARN ethersjs No license field.

+ ethers@4.0.45
added 15 packages from 11 contributors and audited 26 packages in 1.794s
found 0 vulnerabilities

ニーモニックフレーズと、秘密鍵とアドレスを作成する

ethers.jsでニーモニックフレーズとprivatekey, addressを作成します。

const ethers = require('ethers');
// randomなニーモニックフレーズを作成する
const wallet = ethers.Wallet.createRandom();
console.log("mnemonic:" + wallet.mnemonic)
console.log("privateKey:" + wallet.privateKey)
console.log("address:" + wallet.address)

上記をmnemonic.js として保存。実行します。

$ node mnemonic.js 
mnemonic:maze noodle finish dinosaur flight demise double whisper cycle token curve erosion
privateKey:0xe93cea93c2e27672ebdb6b5e69031ffc0302ee025fe82751ef5f2978a977128c
address:0x3CbDbAfE2585F4991CEf5A5D2870F68D661b3943

ニーモニック秘密鍵、アドレスがそれぞれ出力されました。

BIP44準拠のHDWalletを作成する

作成したニーモニックフレーズからBIP44準拠のHDWalletを作成します。

BIP44準拠のHDWalletは、拡張秘密鍵秘密鍵とチェーンコード)からHDWalletのパスを指定して一意な秘密鍵を作成する機能です。 HDWalletのパスとして

"m/44'/60'/0'/0"

などを指定して秘密鍵を作成します。以下コードで鍵を作成します。

const ethers = require('ethers');
// 先ほど作成したニーモニックフレーズ
const mnemonic = "maze noodle finish dinosaur flight demise double whisper cycle token curve erosion"
const hdnode = ethers.utils.HDNode.fromMnemonic(mnemonic);
const nodeA = hdnode.derivePath("m/44'/60'/0'/0");
const nodeB = hdnode.derivePath("m/44'/60'/0'/1");

console.log(nodeA)
console.log(nodeB)

上記をhdwallet.js として保存。 実行します。

$ node hdwallet.js 

HDNode {
  privateKey:
   '0xfea15e2e0cff04bcb0c54de19e617a5e6178c551e343433c1a6f84f7f6c01790',
  publicKey:
   '0x023f0cae7ce16a571097b709aa5a229892d74295721b84b96077c29c55495b48d7',
  parentFingerprint: '0x912096c1',
  fingerprint: '0x8e1a6902',
  address: '0x88216E17AE29A05895A5DbC97296e65B4A85AFdF',
  chainCode:
   '0x3b483d38512ccba9ba949e50c1f98a020bcd38340721c3380d112ffefac6fea9',
  index: 0,
  depth: 4,
  mnemonic:
   'maze noodle finish dinosaur flight demise double whisper cycle token curve erosion',
  path: 'm/44\'/60\'/0\'/0' }
HDNode {
  privateKey:
   '0x85c212b45a45a31b9eec2a46ade91d83454fa33bb2b4c5a70822f6e0ef9069cb',
  publicKey:
   '0x0206d41e7f2db2c35a682d9cfb1d4df5ff6a62b922719b7af5238056eb38a704b7',
  parentFingerprint: '0x912096c1',
  fingerprint: '0xd537fbb6',
  address: '0x3Ec831F1bD67483B8CddAE3EE7de87B49c69E032',
  chainCode:
   '0x1546ec7f08949daf1b8714e26ff5c178a13f46aaf5f84e25ced903d96e583efc',
  index: 1,
  depth: 4,
  mnemonic:
   'maze noodle finish dinosaur flight demise double whisper cycle token curve erosion',
  path: 'm/44\'/60\'/0\'/1' }

秘密鍵、アドレス、チェーンコード、Walletpathなどの一式が簡単に出力できました。

まとめ

EthereumでNode.jsを用いた鍵管理系はethers.jsで簡単に実現できそうです。( ethereumjs-wallet などもあるようですが)

web3.jsとtruffle-hdwallet-provideなどを組み合わせて使う場合、少し相性が悪い時もあったのでこちらをweb3.jsの代替として使う選択肢もありそうです。