lesson-1_ウォレットを作成しよう
👛 HD ウォレットについて
このセクションでは、HDウォレットと呼ばれる種類のウォレットを構築します。HDとは階層的決定性(Hierarchy Deterministic)の略です。
これは簡単に言うと、1つのシードからマスタキーとなる秘密鍵を生成し、そこから木構造のような階層的に複数の派生秘密鍵と派生公開鍵及びアドレスを生成します。
最初の秘密鍵は、シードと呼ばれるランダムな文字列から作ります。その後は作った秘密鍵をシードとして新たな秘密鍵を階層的に作ることができます。
シ ードは覚えにくい文字列ですので、シードから「シードフレーズ」や「リカバリーフレーズ」などと呼ばれる、12個から24個の単語に変換して記録しておく方法が使われています。
参考: 暗号資産におけるウォレットとは ② 〜HD ウォレット編〜
⏬ BIP39 ライブラリを追加する
ここからは、components/GenerateWallet/index.js
ファイルを更新してGenerateWalletコンポーネントを作成していきます。
フレーズを生成するには、決定論的なキーのフレーズ生成の標準を設定したBIP39仕様
を満たす外部ライブラリを活用する必要があります。
JavaScriptには BIP39
と呼ばれるライブラリがあるのでこれを利用していきましょう。
BIP39
ライブラリは、フレーズを生成し、それをSolanaウォレットキーの生成に必要なシードに変換するために必要な機能を提供してくれます。
BIP39
ライブラリをnpm install
する
npm install bip39@^3.1.0
- importする
ライブラリのインストールが完了したら、 ファイルの先頭でライブラリを読み込みましょう。
import * as bip39 from "bip39";
🏭 ニーモニックフレーズを生成する
BIP39
にはニーモニックフレーズを生成するためのメソッドgenerateMnemonic
があります。これを呼び出し、変数に格納してみましょう。
const generatedMnemonic = bip39.generateMnemonic();
これにより、ユーザーがメモして安全に保管できるように、ニーモニックフレーズを設定し、表示することができます。フレーズそれ自体で、その所持者はそのフレーズに一致するアカウントにアクセスすることが可能になります。
🔐 キーペアとシード
ブロックチェーン上のアカウントに接続する前に、このニーモニックフレーズをブロックチェーンが理解できる形に変換する必要があります。ニーモニックフレーズは、長くて古風な数字を、より人間に近い形に変換する抽象的なものなのです。
@solana/web3.js
ライブラリがキーペアオブジェクトを生成するためにこのフレーズを使用できるように、フレーズをバイトに変換する必要があります。キーペアは、データを暗号化できる公開キーとデータを復号化できる秘密キー からなるウォレットアカウントとなります。
@solana/web3.js
ドキュメントを確認すると、Keypair
クラスが "An account keypair used for signing transactions." として定義されていることがわかります。これはまさに、ニーモニックフレーズを使用して生成する必要があるものです。
またドキュメントを読むと、 Keypair
クラスには、32バイトのシードからKeypair
を生成するfromSeed
メソッドがあることがわかります。そして、シードはUint8Array
である必要があります。つまり、ニーモニックフレーズをUint8Array
に変換する方法が必要だということです。
BIP39
ライブラリに戻ると、mnemonicToSeedSync(mnemonic)
というメソッドがあり、16進数のリストのようなBuffer
オブジェクトが返されます。このメソッドを実行し、生成したニーモニックを渡すことで、テストすることができます。
const seed = bip39.mnemonicToSeedSync(generatedMnemonic);
console.log(seed);
// > Uint8Array(64)
ゴールまでもう少しです!🥭
Keypair
クラスは32バイトのUint8Array
を必要としますが、現在は64バイトのUint8Array
を取得しています。シードをsliceして、最初の32バイトだけを保持するようにしましょう 。
const seed = bip39.mnemonicToSeedSync(generatedMnemonic).slice(0, 32);
console.log(seed);
// > Uint8Array(32)
正しい形式のシードがあれば、Keypair
のfromSeed
メソッドを使って、アカウントのキーペアを生成することができます。
const newAccount = Keypair.fromSeed(new Uint8Array(seed));
console.log("newAccount", newAccount.publicKey.toString());
// > ランダムな文字列
👛 ウォレット生成関数を定義する
これまでの説明を踏まえて、ウォレットを生成するための関数generateWallet
を定義します。それでは、components/GenerateWallet/index.js
を更新していきましょう。
まずは、下記のインポート文を追加します。
import { Keypair } from "@solana/web3.js";
import { useState } from "react";
次に、export default function GenerateWallet() {
の下に下記のコードを追加します。
const generateWallet = () => {
const generatedMnemonic = bip39.generateMnemonic();
// ニーモニックフレーズを使用して、シードを生成します。
const seed = bip39.mnemonicToSeedSync(generatedMnemonic).slice(0, 32);
// シードを使用して、アカウントを生成します。
const newAccount = Keypair.fromSeed(new Uint8Array(seed));
setMnemonic(generatedMnemonic);
setAccount(newAccount);
};
generateWallet
関数では、ニーモニックフレーズとアカウントの生成を行ってます。
また、生成したニーモニックフレーズとアカウントは、useState
を用いて値を保持します。ニーモニックフレーズは、GenerateWallet
コンポーネント内でのみ表示するため、mnemonic
という状態変数に格納します。アカウントは、複数のコンポーネント間で共有したいので、Home
コンポーネント内で状態変数を定義し、各コンポーネントに必要なものを引数で渡す形にしましょう。
GenerateWalletコンポーネントの引数にsetAccount
を記述し、export default function GenerateWallet() {
の直下に、mnemonic
を保持する状態変数を定義しましょう。
// `{ setAccount }`を引数に追加
export default function GenerateWallet({ setAccount }) {
// 下記を追加
const [mnemonic, setMnemonic] = useState(null);