By Elle Mouton
Source: https://btctranscripts.com/advancing-bitcoin/2022/static-invoices-in-lightning
This article is a transcript of Elle Mouton's speech at the Advancing Bitcoin 2022 conference, transcribed by b3h3rkz.
introduction
Hi, my name is Elle, and I'm going to talk about static invoices in the Lightning Network. As most of you probably know, in the current Lightning Network, if you want to get paid, you need to create a new "invoice" every time. This can be a barrier for people who don't know anything about the Lightning Network. Today, I'm going to talk about why we should aspire to static invoices, and then outline three proposals that people have been discussing: LNURL, Offer, and AMP.
So, this is just a quick overview. I think it's really important to make sure everyone understands what the problem is. So I'm still going to take a moment to introduce Lightning payments. Not a deep dive, but just an overview so that everyone can understand what the prerequisites are for payments to go through the Lightning Network. Then, we can understand the role of BOLT11 invoices. Then I'll talk about the shortcomings of these things and then get into the above proposals. Then, I'll give a summary of the high level and review the arguments that people have been discussing on Twitter. Finally, I'll list some open issues.
Lightning Payments 101
So let's get started. As you probably all know, the Lightning Network is made up of channels. A "channel" is a contract between Alice and Bob that allows them to transfer value between each other as many times as they want, very quickly, and off-chain, based on a 2-of-2 multi-signature script. This is awesome. If there is a channel between any two people in the Lightning Network, then the static invoice problem doesn't exist, and I can end my talk right away.
But if that were the case, the Lightning Network wouldn’t scale — you can’t open a channel with every person you might pay/request payment from (each channel is a UTXO), so this model doesn’t work at all. The beauty of the Lightning Network is that Alice’s view looks a bit like this, and all she needs to do is find a path through the network to Dave if she wants to pay him (without having to open a channel directly with Dave).
Look more closely. Alice is looking for a path to reach Dave, and she only needs to focus on the path. So now, how does Alice pay Dave? Why can't this process be static? Why can't she just order her node to "please pay this person (Dave's node ID) this amount of bitcoins"? That's static.
The most naive way is for Alice to contact Bob: "Hey Bob, please help me. I'll give you some Bitcoin, you take some out of it and give it to Charlie, who then takes some out of it and gives it to Dave." Great, Dave gets paid. But it doesn't work either, because in the Bitcoin world, we can't trust Bob. In fact, if Alice just gives Bob some money like this, there's nothing stopping Bob from just running away with the money. So Lightning Network payments don't work this way either.
So how does it work? Actually, before the payment starts, to put it bluntly, before we use the Lightning Network, Alice says, "Hey Dave, I'm going to pay you, please pay attention." Dave understands what she means, generates a secret value, and then sends the hash of the secret value back to Alice. This all happens outside the Lightning Network. Now, Alice finds Bob again, but this time, Alice will say, "Bob, if you can find the original image behind this hash value, you can get the 3 BTC I gave you. If you can't solve it, then after a period of time, I will take my money back." After Bob sees this information, he knows that he can only get Alice's money by continuing the same pattern, finding Charlie, and finally getting the secret value.
Then he also establishes a conditional payment with Charlie under the same conditions, and Charlie also establishes a contract with Dave under the same conditions. Dave has the secret value, so when he reveals the secret value, he gets payment from Charlie; Charlie can then give the secret value to Bob and get payment from Bob; Bob can then find Alice. At this point, Alice gets the secret value, and Dave also gets payment. This secret value is what we call "payment evidence."
That’s pretty much it for Lightning Payments 101. There are two things you need to be aware of here (well, the same thing actually), so the first is that Alice and Dave must interact with each other outside of the Lightning Network before the payment can actually happen. This brings up the question: why is this?
Dave has to deliver a hash to Alice, but there is more to it than just the hash. This is where the BOLT11 invoice comes in.
BOLT11 Invoice
BOLT11 specifies how Dave should construct the information he sends to Alice. So, any lightning wallet knows how to construct this information, and how to read it. I'm pretty sure you've all seen BOLT11 invoices, usually displayed as a QR code. Note that this is an invoice from the regtest network, which is not safe to pay, as I'll get to shortly.
Let’s take a closer look at what a BOLT11 invoice looks like. There’s the prefix, which indicates that this is a Lightning Network invoice; then there’s the amount that Dave is expecting, a timestamp, some arrays of data (I’ll come back to this later), and then there’s a signature for all of these things.
I already mentioned that one of the data is the payment hash, which is very important because it is the only way to guarantee the integrity of the payment, so this is the first thing. The other data is the node ID.
If Alice walks into Dave's cafe for the first time, she needs to know how to find Dave's node in the Lightning Network, which requires a node ID. Another thing Dave can include in the invoice is called "Hop-Hints", because Alice's network view may be like this, and Dave only has a private channel, which Alice cannot find in the public network view, so Dave has to tell her that he must tell her the UTXO under the private channel so that Alice can find Dave.
The invoice needs to contain these things. It might also contain a description, like "This is for a cup of coffee," and some other information that indicates the characteristics of the node, which is equivalent to Dave saying to Alice: "I can accept payment with these characteristics," and so on.
There are other things, but for my talk today, that's enough. So what's the problem with it?
My main concern is this: it's one-time. I often hear people say, "Invoices are one-time, so, they're not secure." I just want to explain why.
Let's say Alice and Bob both walk into Dave's cafe. Dave generates an invoice because he wants to collect payment. Create a BOLT11 invoice, display the QR code. Alice is in line to sign, so she pays first, as we saw above. Then Dave reveals the secret value, so Alice gets proof of payment for this invoice. But it happens that Bob also sees the invoice at the same time, and thinks it's for him, so he tries to pay it too. So he also steps forward and scans the code to pay.
Now, what if Eve and Charlie are the same person, or they're in collusion? Charlie already knows the secret value when he forwards Alice's payment, and now he just sends that secret value to Eve, and they get the money from Bob. Bob thinks, "Great, I got proof of payment," but Dave doesn't get paid. He only gets paid once. So you can see that if you're paying an invoice, you have to make sure that no one else has paid it before. This is very important.
This leads me to my next conclusion: this is a very weak proof of payment. As I just said, both Alice and Bob get the same proof of payment. So, in reality, having a secret value only proves that the associated payment was completed at some point, not that you have paid it.
There are some other issues. I mentioned already that Dave might need to include a jump note in the invoice. If all his channels are private, this is kind of shooting himself in the foot, because none of them are private anymore. Alice could sell this information. So this is not ideal either.
Another thing is sender and receiver privacy. In this example, I showed that when Alice pays Dave, Dave has no privacy from Alice. Alice knows exactly where her payment is going. But Alice has a lot of privacy. Dave doesn't know where the payment to him is coming from, unless Alice wants to refund it, which would mean she has to reveal her position in the network; which is certainly not a good option.
Another small detail is that the BOLT11 signature is designed to prove that the issuer created the invoice. It is a signature of the entire invoice (as a flat structure). This is not ideal. If you want to show that the signature is valid, you can only show the entire invoice and expose all the information.
The other thing is the poor user experience. This is a valid BOLT11 invoice with 20 jump prompts. As you can see, this is not ideal. The payer can't scan the code with their phone. And this proves that this model of presenting invoices is very limited. The amount of information Dave can directly show to Alice is very limited. This is a bit awkward.
We're all used to having our money in a bank account that doesn't change. Now, we have to tell users, "Hey, man, if you want to get paid, the person who's paying you has to say hi to you first, and you have to have your node generate a new invoice. Then, you need to send the invoice to that person, and then she'll have her node pay you." Isn't that a bit awkward?
Another awkward thing is the withdrawal process. Let's say Dave is an exchange and you want to withdraw some money from the exchange. Let's say you interact with the exchange on your computer, but your node is on your phone. Now, you have to generate an invoice on your phone, then somehow get the invoice to your computer, and then send it to Dave so that he can pay you. Awkward, still awkward.
Finally, we come to some proposals to solve this problem.
LNURL
But having said that, I am still mainly concerned with payment scenarios, and I will not consider withdrawal scenarios for the time being. So, "LNURL", simple and beautiful. LNURL is basically a set of specifications that specify different communication methods that Alice and Dave can interact with each other. All the communication methods it specifies occur outside the Lightning Network. What it can do is that in the payment scenario, Dave can use an HTTP server with a static network endpoint, such as "dave.com/payme". This HTTP server will communicate with Dave's node.
Now, all Alice has to do is know about this endpoint. As you can see, the endpoint doesn't need to change, it can be static, you can print it out, or you can tattoo it on your body. Alice visits this endpoint, and the HTTP server asks Dave's node to generate an invoice and send it back, which is then passed to Alice's client. Anyone can visit this endpoint and be sure that the invoice they get is unique. This is really great, as you can see, simple and beautiful.
Then, similar ideas can be applied to the withdrawal process. If you want to know more, ask the Coincorner team above, their card uses the "LNURL-withdrawal" protocol. Basically, it allows us to present a code like this and show it to the customer securely. You can't do that with a BOLT11 invoice, that's not secure. Yes, with LNURL, using a static endpoint is secure.
So, what's also interesting is that I can change the parameters of the invoice behind it, and the endpoint itself doesn't have to change. For example, today, I price a beer at 10 satoshis, and tomorrow, I price it at 20 satoshis; but the endpoint itself doesn't have to change, right?
The following is a small plug-in for the "LNURL-pay" protocol, called a "Lightning Address". But the principle behind it is exactly the same, it's just easier to explain over the phone, and it looks like an email address.
Pros and Cons
It’s beautifully simple, and it’s already in service. Many wallets have already integrated LNURL. And there’s no need to change the Lightning Network or BOLT11, because the communication happens outside of the Lightning Network. It gives us static invoices that can be put in smaller QR codes, and the payment process is simple and easy to understand.
One big downside is that, as people often say, you need an HTTP server to use LNURL to collect payments. On top of that, if you're not using Tor, you don't understand domain names and TLS certificates, etc. Yeah, it's not ideal for nodes on your phone either (for example).
Another thing is that if you don't use Tor, both the sender and the receiver will have some privacy leaks because you have this server. Earlier I mentioned that Alice enjoys a lot of anonymity because Dave doesn't know where the payment is coming from. But now, she is sending a request to this HTTP server first, so she will reveal her IP address.
Offer
Then there's BOLT12, better known as "Offer," which is a very large proposal with a lot of additional features from Rusty Russell, an engineer at Blockstream. Yes, from a very abstract perspective, it's very similar to LNURL, both in terms of workflow and end result, except for one thing: the invoice retrieval I talked about in the LNURL section happens within the network, which means you don't need an additional HTTP server. So users on mobile phones can use it. The power of it is that, yes, you don't need anything else. Once you start the node, it's ready to go.
Here's a very crude example. This time, what Dave is going to do is create this thing called an "Offer." And this offer can be static, it contains enough information for Alice to find Dave in the lightning network, but it doesn't contain anything that has to keep changing. So it can be static.
Alice can then use this information to find Dave on the Lightning Network and send him an "invoice request". When Dave's node receives this message, it will send the invoice back, also transmitted through the Lightning Network. Now Alice can pay the invoice.
Great, that sounds really cool and simple, but there is a lot of work to do to make this invoice retrieval program work on the Lightning Network. Let’s take a closer look.
First, we need to be able to send messages like this. Communicate in the Lightning Network. OK, so can we leverage existing messaging patterns?
Currently, in the Lightning Network, we have "gossip messages". There are messages that you want to broadcast, you want it to flood the entire network. You want to tell the entire network: "Hey guys, this is a new channel, I'm a new node, my channel utilization requirements have been updated", etc. This is not an ideal way to request an invoice. We don't want the entire network to know that we are requesting an invoice, and we definitely don't want the entire network to see this invoice. Also, gossip messages are severely rate-limited. A large number of nodes will batch the gossip messages they want to send out, which is very slow. You have to wait a long time, which is also not ideal in our scenario.
There is another type of message, which is a payment-specific message. Let's use our previous example. When sending a payment, Alice has to tell Bob and Charlie where to forward the payment and which channel to use. This is closer to what we want because it will send the message along the specific path that Alice chooses. But the problem is that it is a payment-specific message, which will trigger the process of adding HTLCs and the process of invalidating HTLCs. To use this method to send messages, you need to create a payment. However, in fact, people have sent data in the Lightning Network in this way. Just make a fake payment and fill in a random hash value. Dave has no idea it is coming. You add the data you want to send in the payment-specific message, encrypt it (so that only Dave can decrypt it), and send it to Dave. When Dave receives the message, he knows that he doesn't have the secret value at all, but he can decrypt the information you attached to it and make the payment fail. This sends the message. You only need to lock up a small amount of liquidity, and as long as Dave is online, there will be no problem; but if Dave is offline, you will have to wait for the relative time locks of the HTLC in each channel along the way to expire one by one, which is not good for the network.
Well, what this means is that for Offer to work, we need a whole new messaging system to send these new types of messages. That’s where “Onion Messaging in Lightning” comes in. Yes, BOLT12 is built on Onion Messaging. It does exactly what the name says. It allows Alice to send a message to a node in the Lightning Network, and the path that the message takes is determined by her.
Some people might say this is a scam, that in order for a local feature to work, the entire network has to be updated to understand onion messages. But I would say this is not a big deal, because if we can get a lot of benefits from it, and the scale of the Lightning Network is still limited, we can upgrade quickly. And people upgrade really quickly.
You can do a lot more with onion messages, not just the invoice request message and invoice return message we mentioned earlier; think about it, you can send any message. So there are a lot of things you can do, but I won't go into it here, you can continue to focus on this area.
There are other arguments that you may have heard, especially on Twitter, where people often say that this feature (onion messaging) should not be added because it will allow DoS (denial of service attacks). People can bomb the network, people will stream movies through the Lightning Network, etc. This is a big concern that people have, and there is no built-in solution for the current proposal.
Another thing is that Alice cannot - at least not currently - know whether the message has been delivered. This is also more or less a problem. Another thing is that here, Bob and Charlie are helping Alice for free. Because Alice's message is not tied to a payment, they have no real incentive to pass on the message, unless it is out of this idea: "I helped you this time, and you will help me in the future." We know that this is also the case with forwarding transactions in the Bitcoin network.
I would also say stay tuned in this space because in the last two weeks there have been a number of proposals that are intended to protect interfaces from DoS attacks.
Offer has some really cool additional features.
First, I already covered hop hints and why they are a problem (UTXOs that we originally wanted to keep private will be revealed). So, instead of hop hints, Offer uses a "blinded path". This is basically how Dave tells Alice how to find him: Dave gives a blinded path that allows Alice to contact him in the network without revealing her location in the network. I won't go into detail, but it's really worth studying. And it's awesome because now, Alice doesn't need to know Dave's exact location to still pay Dave. Then, if Alice wants a refund, she can provide a blinded path so that he doesn't have to give up his anonymity.
Another really cool thing is "Proof of Payee". In the invoice request that Alice sends to Dave over the network, she includes a key that belongs to her, called the "Payer Key". When Dave sends the invoice back, he needs to commit to the message that Alice sent earlier, and therefore also commit to Alice's key. This means that when Alice gets back S (the secret value behind the hash), this S value can prove that she is the one who sent the payment, because the invoice itself proves that she is the one who requested it. So this is a great proof of payment.
In addition, there are signatures for offer, invoice and invoice request messages: what is signed is a merkle root value, not the entire invoice; the merkle tree is constructed from all the fields in the invoice. So if you need to show the invoice to someone, you can show only the parts you want to show.
No delay in payment
Well, Offer doesn’t solve the stuck payment problem, but I’ll explain it first. What is a stuck payment? I walk into a cafe, get an invoice, I initiate a payment, and it gets stuck; so I ask the store to give me another invoice, and my node initiates a payment through another path, which succeeds this time; but at this moment, the first payment also reports success.
The store can't tell that I only want to pay once. So Offer also takes this into account. So when you make a second invoice request, you can say, "Hey, I want to replace the first invoice." This is still possible, just add some plausible deniability capabilities.
And the interesting thing is that you can specify the amount in other currencies (not Bitcoin), which is good for static endpoints, especially when the price fluctuates wildly. So now you have a static endpoint, and you can say, I'm going to mark the payment amount in US dollars; and then this endpoint can be used all the time. When people, the wallet of the payer needs a conversion rate to pay.
And Offer can also be used to support subscriptions. For example, this is an Offer, it means you will give me a subscription fee every month. And so on. But currently, due to time considerations, this feature has been deleted.
Pros and Cons
What’s great about Offer is that it’s native to the Lightning Network. So the moment you spin up your node, you get this benefit without having to worry about using an additional server. Because of the blinded path, both payers and receivers get better privacy. And, again, because of the static endpoints, we have a better user experience and better proof of payment.
Of course, it also has some disadvantages, such as the need to upgrade the entire network, which I have already mentioned, and I personally do not think it is a big problem. Then, the current problem is that there is no solution designed for DoS protection. Another thing that people often say is that it depends on many things. I have already mentioned onion messages and blinded paths. Yes, if we want to use offers, we have to implement so many things. And it does bring some application-level things to the network, which some people don't like. For example, as I mentioned earlier, using other currencies to specify amounts.
Atomic Multi-Path Payment (AMP)
Before I say anything else, I want to mention that the real power of AMP is that it allows you to atomically use all or part of your channels to initiate a payment. And as a side effect, you can use a static invoice.
Single path scenario
I'm going to talk about static invoices first. Let's use a single-path payment scenario as an example. Originally, Dave wanted to create a BOLT11 invoice; I've already introduced what's in a BOLT11 invoice. The reason you have to create a new invoice every time is that you need to change the payment hash to ensure payment security.
But when using AMP, the payment hash is meaningless, Dave will use the feature bit in the invoice to tell Alice that this is an AMP invoice and you can safely pay it multiple times. Of course, the payer's node needs to understand this feature.
So far, we have assumed that Dave always needs to create a secret value, calculate a hash value, and send the hash value to Alice. But AMP reverses things: Alice generates a secret value and calculates a hash value; she encrypts the secret value so that only Dave can decrypt it; then, she constructs a payment-specific message. When the payment-specific message is forwarded to Dave, he can decrypt the message, get the secret value hidden in it, and then use it to claim the payment; the secret value is sent back all the way.
Great, so we get two things. The first is that Alice can initiate the payment directly without notifying Dave in advance. This allows for spontaneous payments. The second thing is that Alice cannot receive payment proof. Because she knew the secret value from the beginning, which means that the secret value she gets back at the end is meaningless.
Now, now I want to show the real beauty of AMP and use images to show how it works.
Alice may want to use her balance scattered across different channels to pay Dave. So, she first creates something called a "root seed", which is a large volume of data. Then, she will deterministically generate four different secret values and then calculate the hash values of these secret values. Why four? Because she wants to use all four of her channels. Now, she divides the root seed into four parts. In the first path to send the payment, she makes an HTLC with the first hash value and attaches the first part of the root seed. When this payment is delivered, Dave cannot claim the payment because he does not know the secret value behind the hash value.
Only when all four payments arrive can Dave reconstruct the root seed, then deterministically generate the four secret values, and then receive the payment. This is the beauty of it.
Benefits and Disadvantages
Again, static invoices. Only Alice and Dave need to support AMP. This allows Alice to pay directly without contacting Dave first. And, we can reuse BOLT11 invoices. And, you can use all your channels, which is great because if a new user comes in, he has no idea what a "channel" is; the app just shows a balance, and he actually has access to the entire balance. Then, a big disadvantage is that there is no proof of payment.
Conclusion
OK, that's it. This talk is just to show the comparison of various solutions at an abstract level. Then I would like to leave some questions for you.
Let's first look at the internal layers of the Lightning Network. The current BOLT1 to BOLT11 basically cover these layers, networking, sending messages, payment, and invoice construction. At this point, we can't escape the communication of invoices anyway. On top of this, we can develop applications. So, at which layers are the three solutions mentioned above?
LNURL only specifies invoice communication, at least the “LNURL-pay” protocol I mentioned earlier only does this. AMP is just a new type of payment. But Offer spans many layers. It touches many things.
The Offer specification itself doesn't include this, but it does rely on Onion Messaging. It also uses a different invoice format than BOLT11, so it includes a new invoice construct. It also specifies invoice communication. And it also includes some application layer stuff, like specifying payment amounts in other currencies.
So there are a few points to discuss. If you follow the debate on Twitter, there are a few things that people often discuss:
The first is the importance of proof of payment. I've mentioned that the current proof of payment provided by BOLT11 invoices is relatively weak. AMP does not have proof of payment. Taproot and PTLC (point time lock contract) will change all this, they will bring very strong proof of payment. But people still argue about it. One side will say, yes, obviously proof of payment is very important, because when the network becomes very large, you will really, really, really want proof of payment. And the other side will say, how do people use proof of payment now? How often do they use it? You know, many wallets don't even show the payment preimage to the user. So the two sides have been arguing.
Another thing that will be debated is what should be included in the protocol and what should not be included in the protocol? Where do you draw that line?
Also, do we need to keep just one invoicing system? Can we not mix them together?
Do we need a system that can serve every type of user? For example, people say that LNURL is very friendly to merchants because they always run a server, but it is not very friendly to users who just want to use a wallet on their mobile phone. Yes, LNURL works very well on the merchant side, and Offer is very friendly to users who use the Lightning Network on their mobile phones. So, can we have both? Do we need to ensure that there is only one solution?
I am very interested in these questions, so I leave them to you. Thanks.
(over)




