Unified QRs for Bitcoin
No more on-chain and lightning UI tabs. No more wallet interoperability issues. A simple, backwards-compatible way to request bitcoin for on-chain and lightning.
Asking users to choose between on-chain and lightning payments can be confusing — but it's been necessary to maintain interoperability between wallets.
Most wallets either take a lightning-only or on-chain-only approach. Wallets that support both use a tab or toggle for switching between the two formats.
What if we could simplify this so the user doesn't have to make these choices? And how might we do this in a way that maintains interoperability between wallets?
BIP21 Payment URIs with an optional lightning parameter
BIP-21 defines a URI scheme for creating a “payment link”. By default, it includes an on-chain address to send funds to.
BIP-21 was designed to be extensible. The spec allows for optional parameters in the URI. Why can’t one of these parameters be used to include a BOLT 11 invoice, or even a BOLT 12 offer in the future?
Note that every example features uppercase `bech32` strings (bitcoin addresses, invoices, and offers). When a QR code is encoded in mixed mode, it can use alphanumeric mode for the uppercase strings to reduce the resolution of the QR code and make it more easily readable by devices.
Unified QRs for Bitcoin
BIP21 URI with BOLT 11 invoice
This includes an on-chain address and a BOLT 11 invoice. It is easily backwards compatible, but is quite large.
BIP21 URI with BOLT 12 offer
While BOLT 12 is not widely implemented yet, we can see that using an offer instead of an invoice reduces the QR code size significantly.
Standard QR Codes
BIP21 URI with On-chain address
A standard BIP 21 URI, for reference. This has the smallest QR code, but will not work with lightning.
BOLT 11 Invoice
BOLT 11 invoice QR codes are already significantly large, even without the additional data of the BIP21 URI.
Why this technique?
BIP21 is an existing and agreed-upon standard. Most existing on-chain bitcoin wallets already support BIP21. When these wallets scan the QR code on the right, they will retrieve an on-chain address and ignore the Lightning invoice.
For Lightning wallets, adding support should be simple. They just need to know where to look for the Lightning invoice in the BIP21 URI. Wallets can also give a choice of on-chain and Lightning, if the wallet supports both.
This technique is even mentioned in the BOLT 11 spec!
Adoption of the a unified BIP21 QR code for bitcoin is as simple as getting more Lightning wallets, exchanges, and other bitcoin services to support it. See below for the current list of support. You can help by testing your favorite wallets and services for support, or by implementing this BIP21 support in a wallet or service that does not have support.
The most important next step is getting wallets and services to support scanning BIP21 QR codes.
Once there is wide support for scanning in place, wallets projects can decide if they want to roll out support for generating BIP 21 QR codes. Likely, most projects will not default to generating BIP21 QR codes if there is not wide support for scanning BIP21 QR codes first.
How to contribute
How to test a wallet
Testing a wallet or service is easy. Choose a bitcoin app from the list below that has not been tested yet, or choose one that is not on the list. Then, open the app, scan the QR code below, and see what happens.
Interpreting what you see
- If the app is an on-chain only wallet:
- If the app fails to scan the QR code, then it can NOT scan BIP21 QR codes. Lightning is not applicable in this case.
- If the app successfully scans the QR code and recognizes the "bc1q..." address, then it CAN scan BIP21 QR codes. Lightning is not applicable in this case.
- If the app supports Lightning:
- If the app scans the QR code but tries to initiate an on-chain payment using the "bc1q..." address, then it CAN scan the BIP21 QR code but can NOT recognize lightning.
- If the app scans the QR code and tries to initiate a Lightning payment, then it CAN scan the BIP21 QR code and CAN recognize Lightning.
Optional: you may also document if the app is capable of creating a BIP21 payment URI when you request a payment. The way to determine if a QR code is a BIP21 URI is to decode the QR and see if it begins with
bitcoin:. If this is too advanced for you or you are otherwise unsure, you can simply say "I'm not sure" for this detail; this will most commonly be a no for most wallets today.
Once you have your results, submit a PR to update the wallet_support.json file on GitHub. If you are not comfortable working with the code, then simply file an issue in our GitHub repo or message us in #unified-qr-code on Slack.
How to implement support
Here's a list of references to help with implementation and testing.
- Peakshift Bitcoin UX Payment Requests Package
- QR Code Generator for Testing
- Test vectors from @prusnak
- Python script for generating test vectors from @prusnak
Software and services supporting BIP21
BIP21 QR codes that contain Lightning invoices can get very large. Here is documentation on how different mobile devices fare when attempting to scan these large QR codes.
These results differ from the results above. Here, we are simply checking if an app is capable of reading the very large QR code, and disregarding whether or not it notices the Lightning invoice.
Common Questions & Concerns
QR code size is very large
The QR becomes large enough to cause scanning difficulties with some devices. This is a valid concern. In fact, BOLT 11 invoices alone also have scan-ability issues on some devices.
BOLT12 offers can significantly reduce the size of the QR code. Additionally, techniques like animated QR codes or NFC could help avoid scanning problems.
Does this take away choice from the user?
In many situations, the user already lacks a choice in the matter. For example:
- If the sending user has an on-chain-only wallet, then they have no choice: they can only pay on-chain.
- If the sending user has a Lightning-only wallet, then they have no choice: they can only pay via Lightning.
For wallets that support both on-chain and Lightning, it would be helpful to the user to default to the option that offers the lowest fees, which in most cases is going to be Lightning.
In edge cases where the on-chain fees are actually lower than Lightning, then the wallet could opt to send on-chain or even present the user which a choice: "You can save X amount on fees, but this transaction will take longer to confirm. Is this OK?"