-
Notifications
You must be signed in to change notification settings - Fork 116
(ios) Playground: Bolt Card + Phoenix Wallet #665
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
9bf63de
to
e50f888
Compare
1ab6a94
to
ec112e5
Compare
7f1e602
to
d972a95
Compare
9faea14
to
e85329c
Compare
09c40b3
to
2827f1b
Compare
AbstractThe Bolt Card allows for bitcoin payments over the lightning network using a contactless payment card. The original specification (hereby referred to as version 1) uses lnurl-withdraw. The problem with this is that an HTTP server is required, which creates a significant problem for self-custodial wallets. This bLIP provides a new specification (version 2) that does not require an HTTP server, and uses native lightning messaging. MotivationIn the original version, a merchant who scans a bolt card will read a URL, which is an address for lnurl-withdraw. The merchant then basically generates a Bolt 11 invoice, and ends up sending it to the HTTP server, which is then trusted to forward it to the self-custodial wallet. The wallet user must fully trust the HTTP provider, because it would be very easy to replace the merchant's invoice and steal funds. Providing this HTTP service may also introduce possible legal risks & complications. But to put it simply: there's technically zero reason to use lnurl-withdraw anymore. With Bolt 12 standardized we now have all the tools we need. A merchant can send the invoice directly to the wallet via an onion message, routed over the lightning network itself. This removes the need for an HTTP server, while also increasing privacy for the wallet. Protocol OverviewBolt 12 introduces "offers", which encapsulate a way to communicate with another node over the lightning network. This is generally used to send an invoice-request (meaning offers can function as a reusable "address" for receiving payments). But we're going to use offers for a slightly different purpose. Version 2 works by writing the wallet's offer to the Bolt Card. Thus, when the merchant reads the card they'll see:
Since the merchant has a bolt 12 offer, this means they can send a message to the wallet directly over the lightning network. In this case the message will be a payment-request which will include:
The wallet will receive the onion message, and will validate the card's dynamic values. It can then decide whether to make the payment based on other factors (e.g. has card been frozen). When the merchant receives the payment, it can associate that payment with the bolt 12 offer of the wallet. This allows the merchant software to issue a refund without requiring any interaction from the payer. Bolt Card ContentFor version 2, the value written to the bolt card must be a standard NDEF message with well-known type: TEXT. (The language identifier will be ignored. It's recommended to use "en".) The text content can either be:
Bolt 12 offerIf writing an offer to the card, the text must start with "lno". Thus the format of the read value should be:
While an offer is generally preferable to a bip-353 address, it might not always be possible. Specifically, the card only has 256 bytes of storage for the template string. But you'll need 2 bytes for the NDEF filesytem header, and 7 bytes for the NDEF message header. Plus you'll also need space for the BIP-353 addressIf writing a bip-353 address to the card, the text must start with "₿". Thus the format of the read value should be:
Query parametersThe "query parameters" must not be an empty string (must have at least one character). But other than that, this specification does not enforce the format of that data. It's up to the wallet to decide. For example, you could follow the example from above:
or change the names:
or even just squish it all together without using the common "query parameters" format:
Scanning a Bolt CardWhen the merchant scans the bolt card, they should expect to find either V1 or V2. Version 1 is a NDEF message with well-known type: URI. While version 2 is a NDEF message with well-known type: TEXT. For version 2, the TEXT must either start with "lno" or "₿". Otherwise the card must be treated as a non-bolt-card. Hybrid versionFor wallets that already support V1, they can start to support V2 by adding a "v2" query parameter to the URL. For example:
The
For example, from the URL above:
Merchant processingIf the V2 value is a BIP-353 address, then the first step will be to resolve that address to a Bolt 12 offer. Once the merchant has the offer, it will then generate an unsolicited Bolt 12 invoice. That is, an invoice not based on an
One additional TLV is added to unsolited invoice:
Where the value is the extracted query parameters. E.g.:
Note that this value should be treated as a generic string. The merchant shouldn't make any assumptions concerning it's format. The data must be encoded as UTF-8. The merchant then generates an onion message, where the final-hop is the owner of the offer. The
That is, the value for the final hop is the unsolicted invoice, including the RecommendationsIt's recommended that the merchant software store the base value that was read from the card (either the offer or bip-353 address), and associate this information with the received payment. This allows the merchant software to issue a refund without requiring any interaction from the payer. Thus alleviating a common pain point for merchants (and upset customers). Client processingWhen the client receives the
If all checks pass, it's free to send the payment for the Bolt 12 invoice. |
The Bolt Card allows for bitcoin payments over the lightning network using a contactless payment card.
This PR:
This is a playground / draft PR, with the goal of developing and testing Bolt Card version 2 - a new version that replaces LNURL with modern lightning network communication.
There's a LOT to explain here, so I've broken it down into sections.
User Experience
It's super easy to link a card to your wallet. Just tap the "create new debit card" button, and then tap the card to the upper-half of the iPhone.
nfc_write_720p.mov
After that the user is free to manage their card however they want:
When they make a payment with the card, they will see a notification on their phone:
NTAG 424 DNA
The NFC card that's used is called NTAG 424 DNA
This type of card can be used for many different things. But it also has the attributes needed to perform card payments. In particular, it has AES encryption plus a built-in counter that gets incremented everytime the card is read.
Here's the cliff notes version of how it works:
When you program the card, you write:
Then when the card is read, it will:
counter
variablepicc
data:cmac
(message authentication code):Then general idea is:
Common misunderstanding:
The card does NOT have a static value. The card has a built-in counter that gets incremented automatically. So everytime the card is read, it will output a different value. And within the encrypted value is an incremented counter. This protects against replay attacks.
Lnurl-Withdraw
The Bolt Card was initially released several years ago. Long before Bolt 12 was standardized and widely deployed. Thus it's completely understandable that they opted to use lnurl-withdraw.
However, the use of lnurl-withdraw means:
There's not many problems with this design if you're operating a custodial wallet service. But if you're designing a non-custodial wallet, then there are lots of problems. Thus the desire for an updated version that takes advantage of modern lightning technologies.
(Similar to how BIP-353 is replacing lnurl-pay for lightning addresses.)
Host Card Emulation (like Apple Pay)
It is my understanding that we do NOT need any special permission from Apple to allow either reading NFC cards, or writing to them within our app.
This is in stark contrast to doing Host Card Emulation, where the phone itself acts as an NFC card, and sends data to a reader (i.e. like when using Apple Pay)
However, you must obtain special permission from Apple to use this technology. Here's the details for obtaining permission in the European Economic Area. And here's the details for obtaining permission in the USA.
However, note that even if Apple decides to give you permission to use the technology, it can only be used in an "eligible territory", which Apple decides. And there are more people in the world living outside these "eligible territories" than inside.
Task List: