Node.js
Monacoin
Monaparty

MonapartyアドレスのUTXOをお手入れしましょう

オシャレはUTXOから

みなさん。MonapartyアドレスのUTXOのお手入れ、ちゃんとやっていますか?
UTXOはオシャレの基本。毎日欠かさずお手入れしましょう。

まずは自分のUTXOをチェック!

ワンランク上の自分を目指すためにはまず今の自分を理解することが大切。次のコマンドで自分のUTXOを取得してみましょう。MLJ11FmnsikavGbcHm9HpfgcPhA81NdBzMを自分のアドレスに置き換えて使ってね!

CounterPartyAPIでUTXOを取得
curl -X POST https://wallet.monaparty.me/_api \
-H 'Content-Type: application/json; charset=UTF-8' -H 'Accept: application/json, text/javascript' \
--data-binary '{ "jsonrpc": "2.0", "id": 0, "method": "proxy_to_counterpartyd", "params": {"method": "get_unspent_txouts", "params": { "address": "MLJ11FmnsikavGbcHm9HpfgcPhA81NdBzM" } } }'

異性に嫌われるダメなUTXOとは?

少なすぎる

UTXOが少なすぎると送金が承認されてお釣りが戻ってくるのを待たなければいけなくなるため、連続でトークンを送ることができません。デキる大人は常にさりげなく必要な数のUTXOを持ち歩いているものです。

多すぎる

大量のUTXOは取得に時間がかかります。トランザクション生成時にもたつく姿を見せたら百年の恋も冷めてしまうというもの。UTXOの数が40を超えないように常に気を配っておきましょう。

出涸らしがいつまでも残ってる

何千回何万回とトークンを送信してきた働き者のアナタ。忙しいのはわかりますが、たまにはUTXOのサイズをチェックしないと大変なことになるかも。何度も使われて送金手数料としても使えない極小サイズになってしまった「出涸らしUTXO」はCounterWalletからだとどうやっても消化することができません。

たとえ出涸らしでもUTXOの取得時間は伸びてしまうので、まずは出涸らしにならないように注意するのが大前提。でもうっかり出涸らしUTXOがたくさん溜まってしまったときはどうしたらいい?そんなときには下で紹介するコードを試してみてね!

2019年の決定版!これが理想のUTXOだ!

UTXOの個数は25個がオススメ

これだけあればフルスロットルでトークンを連続送信してもぜんぜんUTXO不足にならないよ!

各UTXOのサイズは0.1MONA以上にしよう

余裕をもって1MONA以上のサイズで揃えられればさらにGood!街の視線がアナタに釘付けになること間違いなし!

出涸らしUTXOを退治するコード

本題です。nodejsで出涸らしUTXOを無理やり送金します。

clearSmallUTXOs.js
const ADDRESS = process.env['ADDRESS'];
const PRIVKEY = process.env['PRIVKEY'];
const RECEIVE_ADDR = process.env['RECEIVE_ADDR'];

const SMALLAMOUNT_THRESHOLD = 0.01;
const SEND_AMOUNT = 0.1;
const SATOSHI_RATIO = 100000000;
const FEESATOSHI_PERBYTE = 200;

const bitcoinjs = require('bitcoinjs-lib');
const coininfo = require('coininfo');
const ElectrumClient = require('electrum-client');
// coinselect に accumulative を指定すると与えたUTXOのリストの先頭から消化してくれる
const coinselect = require('coinselect/accumulative');

const main = () => {
    const network = coininfo('MONA').toBitcoinJS();
    network.messagePrefix = ''; // HACK
    const electrumClient = new ElectrumClient(50002, 'electrumx1.monacoin.ninja', 'tls');
    const keyPair = bitcoinjs.ECPair.fromWIF(PRIVKEY, network);
    const target = {
        address: RECEIVE_ADDR,
        value: Math.floor(SEND_AMOUNT * SATOSHI_RATIO),
    };
    electrumClient.connect().
    then(() => electrumClient.blockchainAddress_listunspent(ADDRESS)).
    then(filterUTXOs).
    then(utxos => coinselect(utxos, [target], FEESATOSHI_PERBYTE)).
    then(({ inputs, outputs, fee }) => {
        if (!inputs) throw new Error('No input');
        if (!outputs) throw new Error('No output');
        console.log('inputs: ' + inputs.map(input => input.value / SATOSHI_RATIO).join(' '));
        console.log('fee: ' + (fee / SATOSHI_RATIO));
        let txBuilder = new bitcoinjs.TransactionBuilder(network);
        inputs.forEach(input => txBuilder.addInput(input.tx_hash, input.tx_pos));
        outputs.forEach(output => {
            if (!output.address) output.address = ADDRESS; // おつりoutputに宛先を設定
            txBuilder.addOutput(output.address, output.value);
        });
        inputs.forEach((dummy, i) => txBuilder.sign(i, keyPair));
        return txBuilder.build().toHex();
    }).
    then(signedTransactionHex => electrumClient.blockchainTransaction_broadcast(signedTransactionHex)).
    then(txID => console.log('txID: ' + txID)).
    then(() => electrumClient.close()).
    catch(error => {
        electrumClient.close();
        console.error(error);
    });
};

const filterUTXOs = (utxos) => {
    // SMALLAMOUNT_THRESHOLDよりも小さいUTXOだけ集める
    // 最後に端数を吸収するための大きなUTXOを1つだけ含める
    const filteredUTXOs = utxos.filter(utxo => (utxo.value < SMALLAMOUNT_THRESHOLD * SATOSHI_RATIO));
    if (filteredUTXOs.length === 0) return [];
    const maxValueUTXO = utxos.reduce((left, right) => (left.value > right.value ? left : right));
    filteredUTXOs.push(maxValueUTXO);
    return filteredUTXOs;
};

main();

動き

環境変数ADDRESSPRIVKEYに出涸らしUTXOの溜まったアドレスと秘密鍵を、RECEIVE_ADDRに送信先のアドレス(なんでもいい)を指定すると、出涸らしUTXOを無理やりトランザクションに含めて送金してくれます。

SMALLAMOUNT_THRESHOLDは出涸らしとして扱うUTXOのサイズ、SEND_AMOUNTはトータルの送金額なので、このへんも適宜調整してください。

コツ

electrumClientで取得した全UTXOのリストからfilterUTXOsで出涸らしUTXOだけ抽出してcoinselectに渡しているところと、coinselectを'coinselect/accumulative'でロードすることでリストの先頭からUTXOを使うようにしているところがポイントです。

この記事はどんな人向けだったの?

何千回何万回とMonapartyトークンを送信してきた結果として出涸らしUTXOがたくさん溜まってしまったけれど、そのアドレスでサービスを運営しているため簡単には新しいアドレスに乗り換えることができない人。つまり、モナパちゃん向けです。ごめんね。

1MONAあるだけで1,000回以上はトークンを送ることができるので、普通の人間はまずほとんど出涸らしUTXOに困るということがありません。BTC/本家CounterPartyなら普通にありえるのかな?

おわり