Skip to content
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

Bolt12 support #1727

Open
wants to merge 49 commits into
base: master
Choose a base branch
from
Open

Bolt12 support #1727

wants to merge 49 commits into from

Conversation

riccardobl
Copy link
Member

@riccardobl riccardobl commented Dec 14, 2024

Description

This PR adds support to pay, estimate fees and decode bolt12 invoices and a bolt12 wallet attachment.
The codebase uses the bolt11 nomenclature pretty much everywhere. After this PR, some areas will be generalized to also account for the possibility of a bolt12 invoice. However, to avoid weighing this PR down with unrelated, mostly graphical or naming changes, I’ve decided to leave those changes for a follow-up PR.

Closes #1317

Screenshots

image
image
image

Checklist

Are your changes backwards compatible? Please answer below:
yes

On a scale of 1-10 how well and how have you QA'd this change and any features it might affect? Please answer below:

For frontend changes: Tested on mobile, light and dark mode? Please answer below:

Did you introduce any new environment variables? If so, call them out explicitly here:
yes

Testing

How to get a bolt12 offer string:

  • wait for eclair channels to be confirmed
    • bash sndev cli eclair channels should return at least 1 channel marked as NORMAL
  • get the tipjar offer string: bash sndev cli eclair tipjarshowoffer
  • see channels balance with bash sndev cli eclair usablebalances

Tests

  • attach bolt12
  • p2p to bolt12
  • withdraw to bolt12
  • lnurlp to proxies bolt12
  • do not allow direct lnurlp to bolt12
  • max_fee

Regression tests

  • pay to sn bolt11
  • deposit to sn bolt11
  • lnurlp to sn bolt11
  • p2p to bolt11 attachment
  • withdraw to bolt11
  • lnurlp to attached bolt11 (direct)
  • lnurlp to attached bolt11 (proxy)

api/lnd/index.js Outdated Show resolved Hide resolved
lib/bolt11-tags.js Outdated Show resolved Hide resolved
return invoice.startsWith('lni1') || invoice.startsWith('lno1')
}

export function bolt12Info (bolt12) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the bolt12 equivalent of the bolt11Tags helper.
Similar to the bolt11 counterpart, i've used a light parser just for the few tags we need in the ui, since the lndk parser needs access to the grpc endpoint.

I couldn't find an established pure js bolt12 parser, so i wrote a small tlv parser (@/lib/tlv) following the specs.

lib/lndk.js Outdated
}
}

const out = {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function converts the output from lndk to an object with a layout compatible with the output from ln-service.

I've followed the doc so it should match the output very closely, but honestly i don't like the fact that ln-service returns so many values that mean the same thing with different types (eg, tokens, mtokens, safe_tokens...), i've implemented this conversion because it makes our code simpler with fewer changes, since we can handle both bolt11 and bolt12 invoices in the same way, but imo we should provide our own abstraction at some point, using only bigint msats and things that make more sense for our codebase.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, ln-service tries to make the grpc interface nicer, but it isn't as well documented as the grpc interface so it ends up just being confusing most of the time.

lib/lndk.js Outdated
response_invoice_timeout: timeout
}, async (error, response) => {
if (error) return reject(error)
const bech32invoice = 'lni1' + bech32b12.encode(Buffer.from(response.invoice_hex_str, 'hex'))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bolt12 invoices are not supposed to be presented to the user, so the spec doesn't define an human readable representation, instead it is left to apps and nodes to handle the representation how they see more fit.
LNDK uses an hex string, while CLN use bech32.
For consistency with bolt11, i've decided to convert them to bech32 like in CLN.

@riccardobl riccardobl changed the title Bolt12 wallet attachment Bolt12 support Dec 18, 2024
@riccardobl riccardobl marked this pull request as ready for review December 18, 2024 16:45
@riccardobl riccardobl added wallets feature new product features that weren't there before labels Dec 20, 2024
Copy link
Member

@ekzyis ekzyis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested normal and automated withdrawals and they work well!

But I noticed the followings things I mentioned in comments that I'd like to see discussed before approval:

  1. lib/ was meant to be files that the server and client can import. Can we use dynamic imports so we don't need to split bolt files by server and client and can have just one file per bolt?

  2. how did you test max_fee?

  3. duplicate checks via if and schema

  4. function signature of parseBolt12Request

  5. error handling via async callback

  6. add similar function for bolt tags like for payInvoice, parseInvoice, estimateFees?

  7. Showing BOLT12 invoices to the user: I think ideally they would always only see the BOLT12 offer. That's also what other wallets do. Is that possible in this PR or should we keep it for another PR?

  8. mutating the lnd object instead of passing lndk separately in context

  9. LND custom options

I read in the LNDK docs that we need to run LND with custom options:

[protocol]
protocol.custom-message=513
protocol.custom-nodeann=39
protocol.custom-init=39

You've added these options in #1702.

Afaict, this means @huumn needs to configure LND differently in prod. You should have mentioned this since I think this wouldn't have worked as-is in prod. 👀

  1. other small stuff (see comments)

wallets/bolt12/index.js Outdated Show resolved Hide resolved
export const card = {
title: 'Bolt12',
subtitle: 'receive payments to a bolt12 offer',
image: { src: '/wallets/bolt12.svg' }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: I am not a fan of this (unofficial?) logo. I would prefer to just use text for the protocols but no strong opinion. I let you or @huumn decide.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logo is nice. Given we plan to overhaul the UI/UX flow of this, I don't think it matter much.

wallets/bolt12/index.js Outdated Show resolved Hide resolved
wallets/bolt12/server.js Outdated Show resolved Hide resolved
wallets/server.js Outdated Show resolved Hide resolved
wallets/server.js Outdated Show resolved Hide resolved
wallets/server.js Show resolved Hide resolved
lib/lndk.js Outdated Show resolved Hide resolved
worker/index.js Outdated Show resolved Hide resolved
@ekzyis ekzyis self-requested a review December 28, 2024 15:32
@riccardobl riccardobl marked this pull request as draft December 28, 2024 19:15
@riccardobl riccardobl marked this pull request as ready for review December 30, 2024 18:46
@riccardobl
Copy link
Member Author

needs to be retested because there were a lot of conflicts and dubious merges

@riccardobl
Copy link
Member Author

riccardobl commented Jan 7, 2025

  • changed lndk to be passed to every context instead of using a weak reference
  • fixed some merge conflicts
  • retested everything

should be ready for review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature new product features that weren't there before wallets
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Bolt12 wallet receives
3 participants