Skip to content
16 changes: 16 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: lint

on:
push:
pull_request:

jobs:
pre-commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.x"
- run: pip install pre-commit
- run: pre-commit run --all-files
12 changes: 12 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
exclude: ^vendor/
- id: end-of-file-fixer
exclude: ^vendor/
- id: check-merge-conflict
- id: mixed-line-ending
args: [--fix=lf]
exclude: ^vendor/
45 changes: 45 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@ A user may want to use a proxy destination for an invoice, either because the us

Then, once the user verifies the amount and payment hash, the user can use the proxy invoice wherever the original invoice would have been used and know that the only way for the payment to succeed is for the lnproxy relay to pay the original invoice.

## Decentralized provider discovery over nostr

Historically a user had to already know a relay's URL. [nostr.md](nostr.md)
specifies decentralized discovery over
[nostr](https://github.com/nostr-protocol/nips): providers advertise themselves
with their own fees, limits and direct endpoints, and clients filter and rank
them cheapest-first. Clients prefer an idempotent direct request when available
and can fall back to an encrypted Nostr exchange with proof-of-work spam
protection. The extended request and response objects are shared by both
transports.

## Requesting and verifying a proxy invoice

1. User makes a POST request to a relay like:
Expand Down Expand Up @@ -87,3 +98,37 @@ An lnproxy relay needs to ensure that payments to the original invoice expire be
### Atomic multi-path payments

Relays cannot create proxy invoices for AMP invoices since there is not payment_hash reveal mechanism.

### Shared payment hash and self-loops

Because the proxy invoice and the original invoice share a payment hash `H`, the
same `H` can legitimately appear on two payments at once: the payer's payment to
the relay (proxy invoice) and the relay's payment to the original destination.
This is fine even when both payments traverse the same node, and even when the
**original destination is the payer itself** (or a node behind it), for example
a payer that wraps an invoice addressed to its own node in order to rebalance or
to hide behind the relay. BOLT 2/3 do not require payment-hash uniqueness across
HTLCs, so a node can hold an incoming and an outgoing HTLC with the same `H` in
opposite directions.

This is safe for the relay regardless of topology, and the safety comes entirely
from the CLTV timeline, not from the destination being different from the payer:

- The proxy invoice's `min_final_cltv_expiry` is set larger than the route the
relay needs to pay the original invoice (see above), so the relay's outgoing
HTLC expires before its accepted incoming HTLC.
- When paying the original invoice the relay sets its outgoing CLTV limit to the
accepted HTLC's remaining delta minus a safety margin (`CltvDeltaAlpha`), so
the relay always learns the preimage in time to settle its incoming HTLC.

In the self-loop case the payer simply learns the preimage (it created the
original invoice) and reveals it when the relay's payment reaches it; that is
exactly the intended preimage flow and lets the relay settle. The payer cannot
claim the relay's outgoing payment without revealing the preimage, and revealing
it lets the relay claim the incoming payment, so there is no way for the payer to
make the relay lose funds.

Implementations MUST keep a non-zero CLTV safety margin and MUST NOT pay out
when the accepted HTLC's remaining CLTV delta is not strictly greater than that
margin (otherwise a maliciously short incoming HTLC, or an arithmetic underflow,
could erase the margin). The relay should cancel such an invoice instead.
Loading