Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 160 additions & 0 deletions 321.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
NWC-321
======

BIP-321 Lightning Payments
--------------------------

`draft` `optional`

## Summary

This specification defines two optional Nostr Wallet Connect methods for BIP-321:

- `pay` pays a Lightning payment instruction from a BIP-321 URI.
- `receive` creates a BIP-321 URI that contains one or more Lightning payment instructions.

## Motivation

BIP-321 can put multiple payment instructions in one Bitcoin payment URI.

This format lets a client use one payment interface for BOLT11 invoices and BOLT12 offers. The wallet selects the instruction that it supports.

These methods are separate from the NWC core because BIP-321 and BOLT12 support are not available in all wallets.

## Dependencies

Implementations of this specification use:

- [BIP-321](https://github.com/bitcoin/bips/blob/master/bip-0321.mediawiki) for Bitcoin payment URIs.
- [BOLT11](https://github.com/lightning/bolts/blob/master/11-payment-encoding.md) for `lightning` instructions.
- [BOLT12](https://github.com/lightning/bolts/blob/master/12-offer-encoding.md) for `lno` instructions.

## Discovery

A wallet service advertises each supported method in its NWC info event and `get_info` response.

A wallet service can implement `pay`, `receive`, or both methods. An implementation of `pay` MUST support `lightning` or `lno` instructions.

An implementation of `receive` MUST return at least one `lightning` or `lno` instruction.

## BIP-321 processing

The wallet service MUST parse the URI according to BIP-321.

The wallet service MUST make sure that the Bitcoin network matches before payment. It MUST reject a payment instruction for a different network.

A URI can contain `lightning`, `lno`, or both instruction types.

If the URI contains multiple supported instructions, the wallet service MUST select and pay only one instruction.

The wallet service MUST report the selected instruction in `instruction_type`.

The wallet service can support other BIP-321 payment instructions. Support for other instructions is outside this specification.

The wallet service MUST reject a URI if it cannot select a supported payment instruction. It MUST also reject unknown required parameters as BIP-321 specifies.

The wallet service MUST apply the BIP-321 rules for `pop` and `req-pop`. The NWC response does not replace a required proof-of-payment callback.

If the wallet service cannot safely open a `req-pop` URI, it MUST reject the request before payment.

## Methods

### `pay`

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Should this be called pay_bip321?

I think of "pay" as the highest-level, most general "here's a payable thing, pay it" API possible.

Here are all the things that the pay endpoint supports in our SDK, for example:

  • BIP 321 URI: bitcoin:bc1...
  • Lightning URI: lightning:ln...
  • BOLT 11 invoice: lnbc1...
  • BOLT 12 offer: lno1...
  • Onchain bitcoin address: bc1...
  • Human Bitcoin Address: ₿username@lexe.app
  • Lightning Address: username@lexe.app
  • LNURL: lnurl1... or lnurlp://domain.com/path

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Originally was but everyone thought it'd be better to do as just pay as we hope to move this to be the standard function you call

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I guess this shifts the work of payment uri parsing and resolution from the NWC client to the server, which makes more sense and is more secure anyway - better to have clients make the resolution requests rather than have the server (which is holding the keys and the Lightning funds) open direct TCP connections to potentially-malicious webservers. And BIP 321 is flexible enough to support this - everything I listed above can be first resolved into a more direct form (HBA -> offer for example) and then passed into pay as a BIP 321 URI.


Pays one Lightning payment instruction from a BIP-321 URI.

Request:

```yaml
{
"method": "pay",
"params": {
"payment": "bitcoin:?lno=lno1...", // BIP-321 URI, required
"amount": 123000, // amount in msats, required if the selected instruction has no amount
"payer_note": "string", // payer-provided message, optional
"metadata": {} // optional metadata as defined in 06.md
}
}
```

The wallet service MUST reject conflicting or invalid amounts before payment.

If `payer_note` is not empty, the selected instruction MUST support payer-provided messages. The wallet service MUST deliver the note or reject the request before payment.

For a BOLT12 offer, the wallet service performs the invoice request and invoice retrieval.

Response:

```yaml
{
"result_type": "pay",
"result": {
"transaction_id": "string", // wallet-scoped transaction identifier
"state": "settled", // "pending", "settled", or "failed"
"instruction_type": "bolt12", // "bolt11" or "bolt12"
"amount": 123000, // paid amount in msats
"fees_paid": 1000, // paid fees in msats
"payment_hash": "string", // optional if unavailable
"preimage": "string", // optional if unavailable
"payer_proof": "lnp1...", // BOLT12 payer proof, optional if unavailable
"txid": "string", // on-chain transaction identifier, optional if unavailable
"failure_reason": "string", // optional unless state is "failed"
"created_at": unixtimestamp,
"settled_at": unixtimestamp // optional unless state is "settled"
}
}
```

The `transaction_id` MUST identify the same transaction in later wallet records.

Errors:

- `BAD_REQUEST`: The URI or another parameter is invalid.
- `UNSUPPORTED_PAYMENT_INSTRUCTION`: The wallet cannot select a supported payment instruction.
- `UNSUPPORTED_NETWORK`: The selected instruction uses a different Bitcoin network.
- `PAYMENT_FAILED`: The wallet attempted the payment, but the payment failed.

The wallet service can also return applicable NWC core errors.

### `receive`

Creates a BIP-321 URI that the client can give to a payer.

Request:

```yaml
{
"method": "receive",
"params": {
"amount": 123000, // amount in msats, optional; omit or use null for a variable amount
"description": "string", // optional
"metadata": {} // optional metadata as defined in 06.md
}
}
```

The wallet service selects the receive instruction or instructions. A client that needs a specific instruction type uses a method for that type.

Response:

```yaml
{
"result_type": "receive",
"result": {
"bip321": "bitcoin:?lightning=lnbc...&lno=lno1...", // BIP-321 URI
"transaction_id": "string", // wallet-scoped transaction identifier, optional
}
}
```

The `bip321` value MUST contain one or more wallet-selected receive instructions. Each instruction MUST use the wallet service Bitcoin network.

If `amount` is absent or null, the returned URI MUST accept an amount from the payer.

If `description` is present, the wallet service MUST include it in each selected instruction that supports descriptions.

Errors:

- `BAD_REQUEST`: A parameter is invalid.

The wallet service can also return applicable NWC core errors.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ The core NWC protocol is tracked in NIP-47 for now. This repository reserves `01
| [05](05.md) | Transaction History | Defines the `list_transactions` method for optional transaction history listing. |
| [06](06.md) | Metadata Conventions | Defines common metadata keys and limits used by optional NWC features. |
| [07](07.md) | Deep Links | Defines optional mobile deep-link conventions for NWC pairing flows. |
| [321](321.md) | BIP-321 Lightning Payments | Defines the `pay` and `receive` methods for BIP-321 Lightning payment instructions. |