Unable to apply spending restrictions to a rune
Problem: how can you issue a rune which restricts the amount of sats that it can spend per request
There have been some loss of funds incidents that have been caused by programs like lnbits and btcpayserver being given unrestricted access to the lightning node. The impact of such incidents could be limited if they were accessing the lightning node through runes that were ratelimited in how much and how fast they could make payments.
PEER_ID=$(lightning-cli getinfo|jq -r .id)
rune=$(lightning-cli commando-rune restrictions='[["method=pay"],["pnameamountmsat<1001"]]' | jq -r .rune)
lightning-cli commando $PEER_ID pay "{\"bolt11\":\"$bolt11_invoice\", \"amount_msat\": 1000 }" $rune
The above creates a rune that can be used to pay bolt11 invoices that do not include an amount. The maximum that can be paid with this rune is 1 satoshi.
The problem is that it will only work for bolt11 invoices that do not specify the amount. If the bolt11 invoice asks for 1 satoshi, the pay command will fail because you cannot specify amount if it is encoded in the invoice:
{
"code": -32602,
"message": "msatoshi parameter unnecessary"
}
Possible solution 1: allow the pay command to specify the amount even when it is not necessary
If we allow the command to be used with a specified amount even when it is encoded in the invoice, I am pretty sure the rune restriction would be applied. Instead of requiring amount_msat to be None, it could be required to be either None or equal to what is encoded in the invoice. This would be the simplest way to solve this problem.
Possible solution 2: allow rune restrictions to apply to bolt11 invoice fields
Runes can look at integer fields and strings to apply restrictions. In this case, we want to make a restriction such that the amount encoded in the bolt11 invoice is less than X.
If runes allowed us to inspect the various fields of the bolt11 invoice, it would be possible to apply a restriction in this way.
Possible solution 3: use getroute and sendpay instead of pay
A possible way to restrict payment sizes would be to not issue a rune for pay but require the use of sendpay instead. With sendpay, I think amount_msat is a required field and so restricting the amount with a rune would work.
I'm not sure if this is what you want to accomplish, but you could write a plugin that intercepts payments done with the pay command and takes a decision to complete the payments based on the amount of the invoice.
See https://lnroom.live/2023-06-08-live-0006-core-lightning-rpc-command-hook-pay-command-and-bolt11-invoice/ for an example.
I'm not sure if this is what you want to accomplish, but you could write a plugin that intercepts payments done with the
paycommand and takes a decision to complete the payments based on the amount of the invoice.
Yes, this is what I want to do.
LNBits, BTCPayserver and Boltcard can all be configured to access a lightning node. If there is a bug or security incident in them, one way to restrict loss of funds is through the use of credentials that have limited access (like runes).
I like the idea of intercepting and inspecting invoices as a plugin is a good idea, but it has one disadvantage: by doing it this way, the application would be given a rune to use the pay command. If the plugin is not loaded or fails, no interception happens and it has full access. So this could set you up for a future vulnerability where you think you have a firewall in place, but after updating the node the plugin is not correctly enabled and so the restriction is lifted.
There are other ways of solving this issue then in 7cbe45b. In fact, it seems kind of redundant: if you just want to pay an invoice, you need to decode the invoice and supply the amount. It might be better if you could just specify a max amount, and then any invoice under this will be accepted.
There is already maxfeepercent and maxfee. Maybe there should be a maxamount_msat.
I want a rune that can pay any invoice up to an amount. If you issue such a rune and rate limit it to 1 time per week with an expiry of 6 days it is in effect a single use voucher much like LNURLw.
But what I really want to use it for is giving LNBits and BTCPayserver the ability to pay invoices up to a limited amount in terms of both sats and rate limit. I nearly have LNBits working using the new CLNRest api as a funding source.
Pretty sure its not possible to take a bolt11 invoice, decode it, remove the amount, encode it as a bolt11 invoice again and then pay that. The reason for this is that I think the bolt11 invoice is signed by the issuing node(?).
So if we have a bolt11 invoice with the amount encoded in it, it is non-trivial to somehow use the pay plugin to pay it but apply a rune restriction.
Decoding a bolt11/bolt12 inside the rune code is non-trivial, however @ShahanaFarooqui convinced me that it's worth trying: we plan on attempting to implement it to judge this week.
https://github.com/ElementsProject/lightning/pull/7165 fixes this issue.
rune=$(lightning-cli commando-rune restrictions='[["method=pay"], ["pinvbolt11_amount<2001"]]' | jq -r .rune)
The above should only be able to pay bolt11 invoices up to and including 2 sats.
With some clever rate limiting, it can be be a great way to give an application limited ability to spend from a core lightning instance.
Now that I know this is likely to show up in a future version of core lightning I will go back to working on making lnbits use runes when communicating over CLNRest.
Thank you!