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` 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 "max_fee": 1000, // maximum routing fee the sender is willing to pay, in msats, optional "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. The `max_fee` parameter caps the total routing fees a wallet service may pay on top of the payment amount. If a route cannot be found whose total cost does not exceed the amount plus `max_fee`, the wallet service MUST NOT send the payment and MUST return a `FEE_LIMIT_EXCEEDED` error. A wallet that honors `max_fee` MUST include `fees_paid` in the response so the client can reconcile against the budget. Wallets that do not implement fee limits MUST ignore the parameter; the client should treat an absent `fees_paid` in the response as a signal that the `max_fee` budget may not have been enforced. 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. - `FEE_LIMIT_EXCEEDED`: No route fit the `max_fee` budget and no payment was attempted. 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.