Coding an alerting mechanism for the blockchain using Node.JS

in #bitcoin8 years ago

For this small project we will use socket.io-client to connect to a BitPay insight server and get real-time notifications on new transactions and blocks. When a transaction includes a relevant Bitcoin address we will send out an email via Mandrill for notification.

Let’s start by connecting to the websocket, you can either use the public insight interface BitPay is maintaining or you could run your own.

var myAddress = '1dice8EMZmqKvrGE4Qc9bUFf9PX3xaYDp'; //This is the address we would like to get alerts for

var socket = require('socket.io-client')('https://insight.bitpay.com');
socket.on('connect', function () {
  console.log('Connected to websocket');
  socket.emit('subscribe', 'inv');
});

The code above will subscribe to the ‘inv’ room which is the room all new tx/blocks are transmitted to.

Now we would like to add a listener to the socket to catch every new transaction and pefrome a check on it

var senttx;
socket.on('tx', function (data) {
  request.get('https://insight.bitpay.com/api/tx/' + data.txid, function (err, head, body) {
    var json = JSON.parse(body);
    json.vout.forEach(function (vout) {
      if (vout.scriptPubKey && vout.scriptPubKey.addresses) { //Avoid any non-standard outputs.
        vout.scriptPubKey.addresses.forEach(function (a) {
          if (a === myAddress) {
            senttx = data.txid;
            sendEmail(data.txid, function (err) {
              if (err)
                throw err;
              console.log('Email sent!');
            })
          }
        });
      }
    });
    json.vin.forEach(function (vin) {
      if (vin.addr === myAddress && senttx != data.txid)
        sendEmail(data.txid, function (err) {
          if (err)
            throw err;
          console.log('Email sent!');
        })
    });
  });
});

The code above will go through each new transaction and check if the address you’ve chosen either sent or received coins and will run the sendEmail function. The senttx variable is used to avoid sending out two emails when the relevant address is in the input and the output fields (For example, if the change address is identical to the input address).

The sendEmail function looks like this

var mandrill = require('mandrill-api/mandrill');
var mandrill_client = new mandrill.Mandrill('YOUR-API-KEY');

function sendEmail(txid, cb) {
  var message = {
    "text": "A new transaction was sent to/from " + myAddress + "\r\nView it here: https://insight.bitpay.com/tx/" + txid,
    "subject": "New transaction for: " + myAddress,
    "from_email": "[email protected]",
    "from_name": "From name",
    "to": [
      {
        "email": "[email protected]",
        "name": "To name",
        "type": "to"
      }
    ]
  };
  mandrill_client.messages.send({"message": message}, function (result) {
    if (result[0].status != 'sent')
      return cb(result);
    return cb(null);
  });
}

That’s all. An email alert will be sent to the defined email address whenever a transaction occurs with the relevant myAddress value.

Full code example

var myAddress = '3MXxfNZoifLYdS8wJTpvfeDNPt9ZWuMAaN';
var socket = require('socket.io-client')('https://insight.bitpay.com');
var request = require('request');

var mandrill = require('mandrill-api/mandrill');
var mandrill_client = new mandrill.Mandrill('YOUR-API-KEY');

function sendEmail(txid, cb) {
  var message = {
    "text": "A new transaction was sent to/from " + myAddress + "\r\nView it here: https://insight.bitpay.com/tx/" + txid,
    "subject": "New transaction for: " + myAddress,
    "from_email": "[email protected]",
    "from_name": "From name",
    "to": [
      {
        "email": "[email protected]",
        "name": "To name",
        "type": "to"
      }
    ]
  };
  mandrill_client.messages.send({"message": message}, function (result) {
    if (result[0].status != 'sent')
      return cb(result);
    return cb(null);
  });
}

socket.on('connect', function () {
  console.log('Connected to websocket');
  socket.emit('subscribe', 'inv');
});

var senttx;
socket.on('tx', function (data) {
  request.get('https://insight.bitpay.com/api/tx/' + data.txid, function (err, head, body) {
    var json = JSON.parse(body);
    json.vout.forEach(function (vout) {
      if (vout.scriptPubKey && vout.scriptPubKey.addresses) { //Avoid any non-standard outputs.
        vout.scriptPubKey.addresses.forEach(function (a) {
          if (a === myAddress) {
            senttx = data.txid;
            sendEmail(data.txid, function (err) {
              if (err)
                throw err;
              console.log('Email sent!');
            })
          }
        });
      }
    });
    json.vin.forEach(function (vin) {
      if (vin.addr === myAddress && senttx != data.txid)
        sendEmail(data.txid, function (err) {
          if (err)
            throw err;
          console.log('Email sent!');
        })
    });
  });
});

socket.on('disconnect', function () {
  console.log('Disconnected!');
});

Alternatively you could also get alerts for large transactions instead of tracking a specific Bitcoin address

var socket = require('socket.io-client')('https://insight.bitpay.com');
var request = require('request');

var mandrill = require('mandrill-api/mandrill');
var mandrill_client = new mandrill.Mandrill('YOUR-API-KEY');

function sendEmail(txid, cb) {
  var message = {
    "text": "A new large transaction was sent\r\nView it here: https://insight.bitpay.com/tx/" + txid,
    "subject": "New large transaction",
    "from_email": "[email protected]",
    "from_name": "From name",
    "to": [
      {
        "email": "[email protected]",
        "name": "To name",
        "type": "to"
      }
    ]
  };
  mandrill_client.messages.send({"message": message}, function (result) {
    if (result[0].status != 'sent')
      return cb(result);
    return cb(null);
  });
}

socket.on('connect', function () {
  console.log('Connected to websocket');
  socket.emit('subscribe', 'inv');
});

socket.on('tx', function (data) {
  request.get('https://insight.bitpay.com/api/tx/' + data.txid, function (err, head, body) {
    var json = JSON.parse(body);
    if (json.valueOut > 100) // Change this value to any amount of BTC you would like to get notifications for
      sendEmail(data.txid, function(err) {
        if (err) throw err;
        console.log('Email sent');
      })
  });
});

socket.on('disconnect', function () {
  console.log('Disconnected!');
});
Sort:  

Thank you kindly. This hidden gem worked for me instantly after hours of trying other methods and attempting to debug the errors.

Congratulations @xabbix! You received a personal award!

Happy Birthday! - You are on the Steem blockchain for 3 years!

You can view your badges on your Steem Board and compare to others on the Steem Ranking

Vote for @Steemitboard as a witness to get one more award and increased upvotes!

Coin Marketplace

STEEM 0.16
TRX 0.15
JST 0.029
BTC 58018.11
ETH 2448.33
USDT 1.00
SBD 2.34