0
Help us understand the problem. What are the problem?

posted at

updated at

bitcoinjs-libでアドレス作成

はじめに

bitcoinjs-libを使う上で、すぐにアドレス作成できたら便利だと思い書きました。
https://github.com/bitcoinjs/bitcoinjs-lib

ニーモニックと拡張鍵生成

getKeys.js
const bitcoin = require('bitcoinjs-lib');
const bip32 = require('bip32');
const bip39 = require('bip39');
const MAINNET = bitcoin.networks.bitcoin;
const TESTNET = bitcoin.networks.testnet;
// let bitcoinNetwork = MAINNET;
let bitcoinNetwork = TESTNET;

function mnemonicToXprivXpub() {
    const mnemonic = bip39.generateMnemonic(256);
    const seed = bip39.mnemonicToSeedSync(mnemonic);
    const node = bip32.fromSeed(seed, bitcoinNetwork);
    const xpriv = node.derivePath("m/44'/1/0").toBase58();
    const xpub = node.derivePath("m/44'/1/0").neutered().toBase58();
    return { mnemonic, xpriv, xpub };
}

const { mnemonic, xpriv, xpub } = mnemonicToXprivXpub();
console.log("mnemonic:");
console.log(mnemonic);
console.log("xpriv:");
console.log(xpriv);
console.log("xpub:");
console.log(xpub);

generateMnemonic(256)だと24語出ます。
generateMnemonic()だと12語です。

$ node getKeys.js 
mnemonic:
task foster wet panther noble tissue hockey ancient faint mandate suit thank mad wrist where category lecture margin wrap evoke desert topic empty include
xpriv:
tprv8gPHaXkdRLgnE1NgPqZPkH1ffYBiQkuAVowFDi5rGDuxj19vuBsD53cmXHxq8u4gmDv9t8a2YaY56roA8KNZRNTNSe6Yv6jVdDhUvxYbcRj
xpub:
tpubDD5KiwnsZiNT7UQUHVDz9gfnEZhea66557Y2WE89gViMZVQhXagoFYEdhSnsRKtJJrv9yAmEkdCUA68GPmPk9W8tdfq5iWU7JpcXpEUfhyL

鍵をプログラム外部のjsonファイルに書いて呼び出すようにします。
拡張秘密鍵と拡張公開鍵は別々のファイルで作成します。

ディレクトリはこれから作成するプログラムと同じです。

xpriv.json
{
    "xpriv": "tprv8gPHaXkdRLgnE1NgPqZPkH1ffYBiQkuAVowFDi5rGDuxj19vuBsD53cmXHxq8u4gmDv9t8a2YaY56roA8KNZRNTNSe6Yv6jVdDhUvxYbcRj"
}
xpub.json
{
    "xpub": "tpubDD5KiwnsZiNT7UQUHVDz9gfnEZhea66557Y2WE89gViMZVQhXagoFYEdhSnsRKtJJrv9yAmEkdCUA68GPmPk9W8tdfq5iWU7JpcXpEUfhyL"
}

拡張公開鍵から公開鍵を得てシングルシグのアドレス3種(P2PKH、P2SH-P2WPKH、P2WPKH)を生成します。

getSingleSigAddresses.js
const bitcoin = require('bitcoinjs-lib');
const bip32 = require('bip32');
const bip39 = require('bip39');
const { xpub } = require('./xpub.json');
const MAINNET = bitcoin.networks.bitcoin;
const TESTNET = bitcoin.networks.testnet;
// let bitcoinNetwork = MAINNET;
let bitcoinNetwork = TESTNET;

const xpub  = "tpubDD5KiwnsZiNT7UQUHVDz9gfnEZhea66557Y2WE89gViMZVQhXagoFYEdhSnsRKtJJrv9yAmEkdCUA68GPmPk9W8tdfq5iWU7JpcXpEUfhyL";

const pubkeyNode = bitcoin.bip32.fromBase58(xpub, bitcoinNetwork);
const pubkey = pubkeyNode.derive(1).derive(0).derive(0).derive(0).publicKey;

function getP2pkhAddress(){
    const address = bitcoin.payments.p2pkh({ pubkey: pubkey, network: bitcoinNetwork, }).address;
    return address;
}

function getP2shP2wpkhAddress(){
    const address = bitcoin.payments.p2sh({
        redeem: bitcoin.payments.p2wpkh({ pubkey: pubkey, network: bitcoinNetwork, })
    }).address;
    return address;
}

function getP2wpkhAddress(){
    const address = bitcoin.payments.p2wpkh({ pubkey: pubkey, network: bitcoinNetwork, }).address;
    return address;
}

const p2pkhAddress = getP2pkhAddress();
console.log("P2PKH:");
console.log(p2pkhAddress);

const p2shP2wpkhAddress = getP2shP2wpkhAddress();
console.log("P2SH-P2WPKH:");
console.log(p2shP2wpkhAddress);

const p2wpkhAddress = getP2wpkhAddress();
console.log("P2WPKH:");
console.log(p2wpkhAddress);

$ node getSingleSigAddresses.js 
P2PKH:
mhJeuuUmHezU6Z4311WGZLVZMV2GTWcPGw
P2SH-P2WPKH:
2N7XBZfKVZ3h9ysFyZLroQpQ5cwxzY25tWE
P2WPKH:
tb1qzwwvqxr2m8l0kt8trnnhaa48awtq45zauflz5y

マルチシグアドレスも作成してみましょう。2-of-3のマルチシグアドレスを作成するためにgetKeys.jsを3回実行して、3つの鍵を得ます。

$ node getKeys.js 
mnemonic:
strong resource record gap leave diesel sleep gadget truck bonus omit slice remind sting tuna choice shoulder post turkey connect crane unhappy various rent
xpriv:
tprv8fcb9d93ydh7areMRdpi3sbbAqxwfJhQcis8ESquQhUUWxanngo8DM5yqCzE4TdFw6RmTbLUQZ42qzF8aBZkfnUxQs4qaHZwSw1NVBb24i3
xpub:
tpubDCJdJ3BJ81NnUKg9KHVJTHFhjsUspdtKC2TuWxtCpyGsMSqZR5ciPqhr1KvkWqgnFncdvmjU3VmKiumDnzQjg2YZvniC11PCz3pNcsHwBGY
$ node getKeys.js 
mnemonic:
finish noble first teach visual document chef crash symbol calm spend frost sad edit tray damp chaos sad boost horn garbage neglect mention wrap
xpriv:
tprv8hAX4Q4XfvsMY6SRLFbVkQSmeTNSpBFB9NhWhPoP6t1G6TnMeBLsMYw6vm8zGQhiNL2GtyK9iaomcghRbB2KS1eqCyH6i353XDjTP5UZq7U
xpub:
tpubDDrZCp6mpJZ2RZUDDuG69p6tDUtNyWS5igJHyuqgX9oevx38GaATY3Yy6sSkdUd4GbKtGxoqE6Hn6jU3Svn243WDuQXxAALEGEh1BpGEfYQ
$ node getKeys.js 
mnemonic:
museum room hidden group crew celery pumpkin net school metal frost light census tag replace welcome flock mimic funny diagram glow impose ecology scatter
xpriv:
tprv8gvJrJutiX5jVzgn29o9GbYSutadrUX4hyDS89ZvhE9LdMC53Lr8rrcKejX9zLnYKQKjKeihmM65jGMYdyGxz91HKGVckFZ4QC9DuJQyswn
xpub:
tpubDDcLzix8rtmQPTiZuoTjg1CZUv6a1ohyHGpDQfcE7VwjTqSqfjfj3MEBppwwDxrqAMdsvvaKfx6NzHhyeUsqfwAFbmYEx598Yvmpb5wh1B3

マルチシグの秘密鍵は本来は別々の人が持っているので、その想定で、別々に秘密鍵を書いたファイルを作成します。

ディレクトリはこれから作成するプログラムと同じです。

xpriv1.json
{
    "xpriv": "tprv8fcb9d93ydh7areMRdpi3sbbAqxwfJhQcis8ESquQhUUWxanngo8DM5yqCzE4TdFw6RmTbLUQZ42qzF8aBZkfnUxQs4qaHZwSw1NVBb24i3"
}
xpriv2.json
{
    "xpriv": "tprv8hAX4Q4XfvsMY6SRLFbVkQSmeTNSpBFB9NhWhPoP6t1G6TnMeBLsMYw6vm8zGQhiNL2GtyK9iaomcghRbB2KS1eqCyH6i353XDjTP5UZq7U"
}
xpriv3.json
{
    "xpriv": "tprv8gvJrJutiX5jVzgn29o9GbYSutadrUX4hyDS89ZvhE9LdMC53Lr8rrcKejX9zLnYKQKjKeihmM65jGMYdyGxz91HKGVckFZ4QC9DuJQyswn"
}

拡張公開鍵は全て同じファイルに記述します。

xpubs.json
{
    "xpub1": "tpubDCJdJ3BJ81NnUKg9KHVJTHFhjsUspdtKC2TuWxtCpyGsMSqZR5ciPqhr1KvkWqgnFncdvmjU3VmKiumDnzQjg2YZvniC11PCz3pNcsHwBGY",
    "xpub2": "tpubDDrZCp6mpJZ2RZUDDuG69p6tDUtNyWS5igJHyuqgX9oevx38GaATY3Yy6sSkdUd4GbKtGxoqE6Hn6jU3Svn243WDuQXxAALEGEh1BpGEfYQ",
    "xpub3": "tpubDDcLzix8rtmQPTiZuoTjg1CZUv6a1ohyHGpDQfcE7VwjTqSqfjfj3MEBppwwDxrqAMdsvvaKfx6NzHhyeUsqfwAFbmYEx598Yvmpb5wh1B3"
}

xpubs.jsonを読み込んでマルチシグアドレス3種(P2SH、P2SH-P2WSH、P2WSH)を生成します。

getMultiSigAddresses.js
const bitcoin = require('bitcoinjs-lib');
const bip32 = require('bip32');
const bip39 = require('bip39');
const { xpub1, xpub2, xpub3 } = require('./xpubs.json');
const MAINNET = bitcoin.networks.bitcoin;
const TESTNET = bitcoin.networks.testnet;
// let bitcoinNetwork = MAINNET;
let bitcoinNetwork = TESTNET;

const pubkeyNode1 = bitcoin.bip32.fromBase58(xpub1, bitcoinNetwork);
const pubkey1 = pubkeyNode1.derive(1).derive(0).derive(0).derive(0).publicKey;

const pubkeyNode2 = bitcoin.bip32.fromBase58(xpub2, bitcoinNetwork);
const pubkey2 = pubkeyNode2.derive(1).derive(0).derive(0).derive(0).publicKey;

const pubkeyNode3 = bitcoin.bip32.fromBase58(xpub3, bitcoinNetwork);
const pubkey3 = pubkeyNode3.derive(1).derive(0).derive(0).derive(0).publicKey;

const pubkeys = [
    pubkey1,
    pubkey2,
    pubkey3,
].map(Buffer => Buffer);

function getP2shAddress(){
    const address = bitcoin.payments.p2sh({
        redeem: bitcoin.payments.p2ms({ m: 2, pubkeys, network: bitcoinNetwork, }),
    }).address;
    return address;
}

function getP2shP2wshAddress(){
    const address = bitcoin.payments.p2sh({
        redeem: bitcoin.payments.p2wsh({
            redeem: bitcoin.payments.p2ms({ m: 2, pubkeys, network: bitcoinNetwork, })
        }),
    }).address;
    return address;
}

function getP2wshAddress(){
    const address = bitcoin.payments.p2wsh({
        redeem: bitcoin.payments.p2ms({ m: 2, pubkeys, network: bitcoinNetwork, }),
    }).address;
    return address;
}

const p2shAddress = getP2shAddress();
console.log("P2SH:");
console.log(p2shAddress);

const p2shP2wshAddress = getP2shP2wshAddress();
console.log("P2SH-P2WSH:");
console.log(p2shP2wshAddress);

const p2wshAddress = getP2wshAddress();
console.log("P2WSH:");
console.log(p2wshAddress);
$ node getMultiSigAddresses.js 
P2SH:
2NGZYty3BtrN9gv4n8y3YLFa1Uos2XffCvR
P2SH-P2WSH:
2N9mgCypNXq8qkx1SHqBkDW4u92rXKsdJjH
P2WSH:
tb1q2adzgyzuy3msvjjfn3pkghf5fnwtwmxcglw3cuk5gvvv3ahmt63qqqa3n6

xprivは今回使いませんでしたが、以下のトランザクションに署名する際に使います。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
0
Help us understand the problem. What are the problem?