Lightning Decoder — the first of (hopefully) many development tools
Throughout my quest of bringing Lightwork to production on Bitcoin’s mainnet, I’ve come across some gaps in the current development workflow of Lightning Network-powered applications. One of the larger gaps I saw was in relation to the use and understanding of the Invoice Protocol (BOLT11 spec), which is core to the network.
The Invoice Protocol is a simple, extendable QR-code-ready protocol for requesting payments over the Lightning Network.
Sometimes referred to as a Payment Request, the format for a Lightning Network invoice uses a bech32 encoding, which is also used for Bitcoin’s Segregated Witness.
The creator of an LN invoice must encode the payment request in bech32 as specified in BIP-0173. The only exception is that the bech32 string can be longer than the 90-character limit specified in the BIP. The receiver of an LN invoice must parse the address as bech32 (without character limit), and must fail if the checksum of the hash is incorrect.
Invoice URI Scheme
For applications that need to interface with LN Payment Requests, it is recommended to use a
lightning: prefix , followed by the BOLT11 invoice encoding, as such:
Note, it’s not
Given that Lightning payments can sometimes fail (due to routing or capacity issues), application developers should also have fallback support for moving transactions onchain. For that, one should leverage the
bitcoin: URI scheme, as per BIP-21, with the key
lightning and the value equal to the BOLT11 invoice encoding.
Though one might be able to understand (or even memorize) the BOLT11 specification, it is usually pretty hard to reason about the many bits of information that make up a single Lightning Network invoice. This is where Lightning Decoder comes into play.
Lightning Decoder is meant to be a one-stop solution for your Lightning Network invoice-decoding needs. It’s where you can decode payment requests and learn all of the information bits involved in its creation. This is key to not only understand how this payment request came about, but also to drill into the details of the payment to ensure parity with your application’s own database of records.
Below is an example of an invoice being decoded through Lightning Decoder:
It provides clear information about which underlying chain this invoice was created in/for, what the desired payment amount is (in satoshis), as well as a timestamp of its creation. This also helps in identifying payee public node keys, transaction signatures and payment hashes which can be verified further.
LN Node & Application State Sync
In lieu of keeping your application state and your Lightning Network node in sync it is common to follow a redundant architectural approach, where each database document holds an array of its relevant LN invoices (expired or not), and each LN invoice holds a version of the ID of the database document it belongs to.
For Lightwork I decided to leverage the ‘description’ field. This is a blank field in the LN payment request that allows for the user to input any text/data/string (similar to a
memo field). After being encoded, that information is invisible to the naked eye. But when decoded you see something along the lines of:
My approach is to enter an identifier string, in this case
Lightwork which allows me to split the string precisely and predictably. The following
5bdd9d… is the ID of the database document this invoice belongs to. This make is easier to connect an LN invoice to its related document when subscribing to payments over the network. I’ve personally heard this approach being used in other applications that accept Lightning payments, which is even further validation of this implementation.
UX for Development Tools
Most application developers tend to be versed in command line applications, and are usually okay using tools that provide sub-optimal user experiences, since they tend to be merely a utility rather than an end product on its own. As an daily user of development tools, I tend to disagree that they can forego (all) decent UX, simply because ‘engineers are tech-savvy and don’t need pleasant products to achieve their implementation goals’.
My goal with Lightning Decoder was to bring pleasant design and utility together, so that developers can not only depend on its functional capabilities, but can also enjoy the experience of using and relying on it daily.
This is the first of (hopefully) many tools that I’ll be deploying as I continue my efforts in building Lightwork. I have already outlined a couple of other gaps in the LN development workflow that seem to allow for the creation of other tools like this. Lightning Decoder is entirely open source, and I aim to introduce new features and capabilities as the Lightning Network continues to evolve and mature.