Lemonade Stand


This tutorial will go over how to accept litecoinz payments via a web site directly to your wallet. We will interact with a ltzcore node from a web browser to receive payment notifications. And we will generate new keys on the server side for each purchase.



Create a Service



Please refer to the [service development document].



 Generate Invoice Page



For our simple application, we're going to have two pages. One page to generate an invoice, and another page to display and pay the invoice.



Let's start with generating an invoice. We'll need a route ( .js ):



LemonadeStand.prototype.setupRoutes = function(app, express) {

 app.use('/', express.static(__dirname + '/static'));

};



LemonadeStand.prototype.getRoutePrefix = function() {

 return 'lemonade-stand';

};



Create a `static` and put an `index.html` in it:

<!DOCTYPE html>

<html>

<head>

 <title>Lemonade Stand</title>

</head>



<body>

 <h1>Lemonade Stand</h1>

 <h2>Invoice</h2>



 <form method="post" action="invoice">

  Amount: <input type="text" name="amount"/> LTZ <input type="submit" value="Generate Invoice" />

 </form>

</body>



</html>



You can access this page at `http://localhost:3001/lemonade-stand`.



Pay Invoice Page



Next we'll need to be able to generate the invoice server-side and display a page to pay the invoice. Back to `index.js`:


var EventEmitter = require('events').EventEmitter;

var fs = require('fs');

var ltzcore = require('ltzcore-lib');

var bodyParser = require('body-parser');



function LemonadeStand(options) {

 EventEmitter.call(this);



 this.node = options.node;

 this.log = this.node.log;



 this.invoiceHtml = fs.readFileSync(__dirname + '/invoice.html', 'utf8');



 // Use 1 HD Private Key and generate a unique address for every invoice

 this.hdPrivateKey = new ltzcore.HDPrivateKey(this.node.network);

 this.log.info('Using key:', this.hdPrivateKey);

 this.addressIndex = 0;

}



inherits(LemonadeStand, EventEmitter);



LemonadeStand.dependencies = ['litecoinzd'];



LemonadeStand.prototype.start = function(callback) {

 setImmediate(callback);

};



LemonadeStand.prototype.stop = function(callback) {

 setImmediate(callback);

};



LemonadeStand.prototype.getAPIMethods = function() {

 return [];

};



LemonadeStand.prototype.getPublishEvents = function() {

 return [];

};



LemonadeStand.prototype.setupRoutes = function(app, express) {

 var self = this;



 app.use(bodyParser.urlencoded({extended: true}));



 app.use('/', express.static(__dirname + '/static'));



 app.post('/invoice', function(req, res, next) {

  self.addressIndex++;

  self.amount = parseFloat(req.body.amount) * 1e8;

  res.status(200).send(self.filterInvoiceHTML());

 });

};



LemonadeStand.prototype.getRoutePrefix = function() {

 return 'lemonade-stand';

};



LemonadeStand.prototype.filterInvoiceHTML = function() {

 var btc = this.amount / 1e8;

 var address = this.hdPrivateKey.derive(this.addressIndex).privateKey.toAddress();

 this.log.info('New invoice with address:', address);

 var hash = address.hashBuffer.toString('hex');

 var transformed = this.invoiceHtml

  .replace(/{{amount}}/g, ltz)

  .replace(/{{address}}/g, address)

  .replace(/{{hash}}/g, hash)

  .replace(/{{baseUrl}}/g, '/' + this.getRoutePrefix() + '/');

 return transformed;

};



module.exports = LemonadeStand;


Let's walk through this. In our constructor we are loading the HTML data into memory. We'll use this later to replace variables. In a normal application, you would probably use a templating engine like Handlebars or Mustache.



We generate a random HDPrivateKey from which all of our invoice addresses will be generated. Normally what you would do is generate this on a separate computer and put the corresponding HDPublicKey on the server. That way if your server is hacked, your litecoinz is still safe!



Each new invoice bumps the addressIndex by 1. This will create a unique litecoinz address for every invoice that is generated.



In `setupRoutes()` we add an express middleware for parsing form data. Then we add a handler for `/invoice`. When the user submits the form from the first page we created, `amount` is passed to this `/invoice` route. We then parse the amount and respond back with the html, replacing our placeholder values with real values.



Here is what `invoice.html` looks like:

<!DOCTYPE html>

<html>

<head>

 <title>Lemonade Stand</title>

 <base href="{{baseUrl}}" />

 <script src="/socket.io/socket.io.js"></script>

 <script src="js/jquery/dist/jquery.js"></script>

 <script src="js/jquery-qrcode/jquery.qrcode.min.js"></script>

 <script src="js/ltzcore-lib/ltzcore-lib.js"></script>

</head>



<body>

 <h1>Lemonade Stand</h1>

 <h2>Invoice</h2>

 <div id="qrcode"></div>

 <p>Please send {{amount}} LTZ to {{address}}</p>

 <h2>Transactions Received</h2>

 <ul id="txids">

 </ul>



 <script type="text/javascript">

  $('#qrcode').qrcode("litecoinz:{{address}}?amount={{amount}}");

 </script>



 <script language="javascript">

  var ltzcore = require('ltzcore-lib');

  var socket = io('http://localhost:3001');

  socket.on('litecoinzd/addresstxid', function(data) {

   var address = ltzcore.Address(data.address);

   if (address.toString() == '{{address}}') {

    var txidsElm = document.getElementById('txids');

    var elm = document.createTextNode('txid: ' + data.txid);

    txidsElm.appendChild(elm);

   }

  });

  socket.emit('subscribe', 'litecoinzd/addresstxid', ['{{address}}']);

 </script>

</body>



</html>



This will generate a QR code with the litecoinz address and amount. It subscribes to the `litecoinzd/addresstxid` event from the `litecoinzd` service for the given address. Every time the address received a transaction, we receive an event over socket.io and we update the data received accordingly.



The file uses ltzcore on the client side to derive the address from the address object. We use bower to install the dependency in `static/js` directory.



Conclusion



So there we've built our very own litecoinz-accepting lemonade stand using ltzcore Node! Please see the [git repository] as reference for all of the code.