ビットコインをnodejsで送信する

ビットコインをnodejsで送信する

ここでは、node.js を用いた Bitcoin の送金処理を解説する。

● 環境設定(environment)

使用するライブラリを定義

require('dotenv').config();

const BN = require('bignumber.js');
const bitcore = require('bitcore-lib');
const explorers = require('bitcore-explorers');
const insight = new explorers.Insight();
const Client = require('bitcoin-core');
const WAValidator = require('wallet-address-validator');
const _ = require('lodash');

const client = new Client({
  host: process.env.BITCOIN_NODE_HOST,
  network: process.env.BITCOIN_NODE_NETWORK, 
  username: process.env.BITCOIN_NODE_USER,
  password: process.env.BITCOIN_NODE_PASS,
  port: process.env.BITCOIN_NODE_PORT,
});

var Bitcoin = function() {
};

※bitcore-explorers(Insight)
ブロックチェーンの状態を問い合わせるために、異なるWeb APIへのHTTPリクエストを実装するBitcore用の実行ファイル。
アドレスのUTXO(Unspent Transaction Output:未使用トランザクションアウトプット)を取得およびBitcoinネットワークにトランザクションをブロードキャストするためのインタフェース。

● 残高取得(getBalance)

承認前トランザクションの送受信量(受信:プラス、送信:マイナス)との合計を算出

Bitcoin.prototype.getBalance = function(address) {

  return new Promise((resolve, reject) => {
    insight.address(address, function (err, addrinfo) {
      const finalBalance = addrinfo.balance +  addrinfo.unconfirmedBalance;
      const balance = addrinfo.balance > finalBalance ? finalBalance : addrinfo.balance;
      if (err) {
        reject(err.message);
      }
      resolve({
        address: address,
        balance: new BN(balance).dividedBy(1e8).toNumber(),
        finalBalance: new BN(finalBalance).dividedBy(1e8).toNumber(),
      });
    });
  });

};

● トランザクション取得(getTransaction)

insight を用いてトランザクション情報を取得

Bitcoin.prototype.getTransaction = function(transactionId) {
  return new Promise((resolve, reject) => {
    insight.getTransaction(transactionId, (err, tx) => {
      if (err) {
        reject(err.message);
        return;
      }

      let from = [];
      for (let i = 0; i < tx.vin.length; i++) {
        if (!(tx.vin[i].addr)) continue;
        from.push(tx.vin[i].addr);
      }

      let to = [];
      for (let i = 0; i < tx.vout.length; i++) {
        if (!(tx.vout[i].scriptPubKey.addresses && tx.vout[i].value)) continue;
        to.push({
          address: _.head(tx.vout[i].scriptPubKey.addresses),
          amount: tx.vout[i].value
        });
      }

      var arr = {
        tx_hash: tx.txid,
        from: from,
        to: to,
        fee: tx.fees,
        confirmation: tx.confirmations,
        executed_at: tx.time
      };

      resolve(arr);
    });
  });
};

● 送金処理(send)

署名を行い送金処理を実行

Bitcoin.prototype.send = function(signature) {
  return new Promise((resolve, reject) => {
    client.sendRawTransaction(signature).then(tx_hash => {
      resolve(tx_hash);
    }).catch(err => {
      reject(err.message);
    });
  });
};

● 送金パラメーター作成(send_param)

入力データから送金に必要な情報を取得し送金パラメータを作成

Bitcoin.prototype.send_param = function(fromaddress, private_key, toaddress1, amount1, toaddress2, amount2, fee) {

  return new Promise(async (resolve, reject) => {

    let preparedTransaction;
    const amountNum1 = Math.floor(new BN(amount1.toString()).multipliedBy(1e8).toNumber()); 
    const amountNum2 = Math.floor(new BN(amount2.toString()).multipliedBy(1e8).toNumber()); 
    const feeNum = Math.floor(new BN(fee.toString()).multipliedBy(1e8).toNumber()); 

    try {

      const transactionBuilder = function(transaction) {
        return transaction
          .to(toaddress1, amountNum1)
          .to(toaddress2, amountNum2)
          .change(fromaddress)
          .sign(private_key);
      };

      preparedTransaction = await this.prepareTransaction(fromaddress, transactionBuilder);

    } catch (err) {
      reject(err);
      return;
    }

    try {

      const serializedTransaction = preparedTransaction
        .fee(feeNum)
        .sign(private_key)
        .serialize();


      client.sendRawTransaction(serializedTransaction).then(txId => {
        resolve({
          transactionId: txId,
          fee: fee
        });
      }).catch(err => {
        reject(err);
      });

    } catch (err) {
      reject(err);
    }
  });
};

アドレス、数量を並べて書く(toaddress1, amount1, toaddress2, amount2)ことで、一つのトランザクションで複数のアドレスに送金することが可能となる。

● 未使用トランザクション取得(prepareTransaction)

insight を用いて UTXO を取得

Bitcoin.prototype.prepareTransaction = function(fromaddress, builder) {
  return new Promise((resolve, reject) => {
    insight.getUnspentUtxos(fromaddress, function (err, utxos) {
      if (err) reject(err.message);
      const transaction = new bitcore.Transaction();
      resolve(builder(transaction.from(utxos)));
    });
  });
};

● 手数料取得(getFee)

手数料を取得し結果を env ファイルに書き出し

Bitcoin.prototype.getFee = function() {
  return process.env.BITCOIN_FEE;
};

● アドレス検証(isAddress)

アドレスの長さが正しいかを検証

Bitcoin.prototype.isAddress = function(address) {
  if (!(WAValidator.validate(address, 'BTC'))) return false;

  return true;
};

● プライベートキー検証(isPrivateKey)

プライベートキーの長さが正しいかを検証

Bitcoin.prototype.isPrivateKey = function(rawPrivateKey, expectedAddress = null) {
  const privateKey = new bitcore.PrivateKey(rawPrivateKey, 'mainnet');

  if (expectedAddress) {
    const address = privateKey.toAddress();
    if (!(expectedAddress === address.toString())) {
      return false;
    }
  }

  return true;
};

● アドレス生成(getAddress)

bitcore を用いたアドレス生成

Bitcoin.prototype.getAddress = function(rawPrivateKey) {
  const privateKey = new bitcore.PrivateKey(rawPrivateKey, 'mainnet');
  return privateKey.toAddress().toString();
};

module.exports = Bitcoin;

● 入力データ

実際に送金を送るための情報。ここに記載した内容をもとに送金元、送金先を決定。

const BTC = require('./BTC');
const btc = new BTC();

const fromaddress = "14myP**********";
    const private_key = "133fe**********";
    const toaddress1 = "1A5jR**********";
    const amount1 = 100;
    const toaddress2 = "13GQG**********";
    const amount2 = 200;
    const fee = 0.01;

    btc.send_param(fromaddress, private_key, toaddress1, amount1, toaddress2, amount2, fee).then(tx_hash => {
      console.log({'tx_hash': tx_hash});
    }).catch(err => {
      console.log("error");
    });
1

仮想通貨取引所のBitGetについて紹介したいと思います。

2

今回は最近使用している仮想通貨取引所の BitGet のトレードの方法を紹介します!

国内から日本円での入金方法を解説しています。 BitGetとは?登録方法は?という人は 前回の記事 をご覧下さい。

3

今回はマイニングで必要、あった方が良いものをご紹介します。 マイニングとは?という方は以下の記事から! CRYPTO LIFE2021.04.01マイニングとは?誰でもできるの?簡単なやり方を公開‼収 ...

4

今回はマイニングをするに至って注意が必要なことをまとめましたので是非ご覧ください。当たり前のことしか書いていませんがマイニング上級者の方も一度見直すという意味でご覧いただければ幸いです。

5

今回はマイニングをするに至って注意が必要なことをまとめましたので是非ご覧ください。当たり前のことしか書いていませんがマイニング上級者の方も一度見直すという意味でご覧いただければ幸いです。

6

Looopでんきは基本料金0円のシンプルプラン。 多くのご契約で毎月実は発生している「基本料金」をなしにして「使った分だけ」をお支払いするため、 電気をあまり使わない人にも、電気をたくさん使う人にもメリットがあります。 さらにいまはオール電化向けの新プランも登場!オール電化ご利用の方はぜひ! WEB上で切り替えを受け付けているので、24時間いつでも簡単に申し込みが可能です。 いくら安くなるのかのシミュレーションもできるので非常にわかりやすい新電力会社となっています。

© 2022 CRYPTO LIFE