bitcoinを低コストで複数のアドレスに送金したい(100アドレス)

2 min読了の目安(約2600字TECH技術記事

ビットコインを大量のアドレスに送金したかったときのメモ

どうやって送ろうか

現状日本の取引所から送金すると手数料が結構かかってしまう。ビットフライヤーの場合は 0.0004 BTC 。
2020/11/28 のレートで700円くらいなので10アドレスに分けて送金するだけで7000円くらい手数料で吹っ飛ぶ。

なので複数の送金を一度にまとめたい。ビットコインのトランザクションは1つのインプットから複数のアウトプットを設定して構築できるためこれを使う。
https://bitcoin.peryaudo.org/detail.html
ちなみに1つのインプットから複数のアウトプットに分けて支払う形式のことをDistributing Transaction と言うらしい、マスタリングビットコイン日本語訳版では分配型トランザクションと訳されている。

で、もちろん日本の取引所からそんなトランザクション作れないし minerfee を自由に設定できず割高になるため一旦どこかの分配型トランザクションに対応したウォレットに移して送金するしかない。

Armory とか使えばいいのだが、

https://bitcoin.org/ja/wallets/desktop/mac/armory/?step=5&platform=mac&user=experienced&important=fees

大量のアドレス入力するの面倒なので適当にプログラム書いてアドレスリスト生成してそのまま CLI で送金実行したい。

となると bitcoin CLI か。管理がめんどうだな、と思ってたら複数送金できて、オンラインウォレットで、REST API から操作できる blockchain.com のウォレットを見つけたので使ってみました。

blockchain.com を REST API で操作する。

よしなに登録してウォレットを作ってログインしたら、security -> Advanced から IP Whitelist に自分の IP Adress と設定しておく。

目的の分配送金機能を使うにはなぜか 直接 REST API を叩くのではなくローカルに REST API サーバーを立ててローカルホストへリクエストを送るので準備

service-my-wallet-v3 をインストールする。

https://github.com/blockchain/service-my-wallet-v3

npm でインストールできる。

$ npm install -g blockchain-wallet-service  

ローカルホストで実行

$ blockchain-wallet-service start --port 3000

README に書いてあるのは古い上にリンク切れててつらい、API ドキュメントはここ

https://www.blockchain.com/api/blockchain_wallet_api
ちなみに API code は発行しなくても大丈夫、っていうか発行申請しても連絡帰ってこないらしい。

僕の目的の 分配型トランザクションは Send Many Transaction と表記されていた。

Send Many Transactions
Send a transaction to multiple recipients in the same transaction.

さっき起動した localhost:3000 に Get リクエストで guid やらなんやらと送信先とそこへの送信額をまとめた json を入れて送れば送金が実行される。fee キーで minerfee を設定できるので手数料も自由に設定できる。

go でこんな感じに書いて送りました。

var URL = "http://localhost:3000/merchant/$GUID/sendmany"
amountAndAdressJson = json.Marshal(amountAndAdress)
	request, err := http.NewRequest("GET", URL, nil)
	if err != nil {
		log.Fatal(err)
	}

	params := request.URL.Query()
	params.Add("password","$PASSWARD")
	params.Add("fee", "$FEE")
	params.Add("from", "0")
	params.Add("recipients", string(amountAndAdressJson))
	request.URL.RawQuery = params.Encode()

	fmt.Println(request.URL.String())
	client := &http.Client{}
	response, err := client.Do(request)
	if err != nil {
		fmt.Println(fmt.Errorf("%v", err))
	}

	defer response.Body.Close()
	body, error := ioutil.ReadAll(response.Body)

公式には PHP のサンプルコードが置いてあります。

一度に 100 アドレスまでしか送れなかった

これである程度目的は達成できたのですが 100 アドレスまでしか一度に送金できないことが判明しました...
100 アドレスが blockchain_wallet の仕様ならいいのですが Bitcoin CLI だとどのくらいのアドレス数まで対応してるのでしょうか🤔