跳至主要內容
高級

Offers Refunds BOLT12 退款

了解 BOLT12 的退款機制,如何實現可退款的閃電支付和商家退款流程。

10 分鐘

什麼是 BOLT12 退款?

BOLT12 引入了原生的退款機制,允許商家向買家發起支付。 這解決了傳統閃電支付「發送後無法退回」的限制。

雙向互動: 退款利用 BOLT12 的互動式協議,商家可以向買家請求發票, 然後支付該發票完成退款。

退款流程

BOLT12 Refund Flow:

Complete Flow (Purchase -> Refund):

  Buyer                                   Merchant
    |                                        |
    |  ======= Normal Purchase Flow =======  |
    |                                        |
    |---- invoice_request ------------------>|
    |     (contains payer_key)               |
    |                                        |
    |<--- invoice ---------------------------|
    |     (records payer_key)                |
    |                                        |
    |==== HTLC Payment =====================>|
    |                                        | [Store order info]
    |                                        |
    |  ======= Refund Flow =======           |
    |                                        |
    |<--- invoice_request -------------------|
    |     (merchant requests buyer invoice)  | [Initiate refund]
    |                                        |
    |---- invoice -------------------------->|
    |     (buyer provides payment invoice)   |
    |                                        |
    |<=== HTLC Payment (refund) =============|
    |                                        |

退款 Offer 結構

send_invoice Offer (for refunds):

Offer Type Comparison:

Normal Offer (receiving payment):
  • Merchant publishes, buyer scans
  • Buyer requests invoice -> Merchant provides invoice -> Buyer pays
  • send_invoice = false (default)

Refund Offer (sending payment):
  • Merchant sends to specific buyer
  • Buyer provides invoice -> Merchant pays
  • send_invoice = true

Refund Offer TLV Fields:

send_invoice (54):
  Present indicates this is a refund Offer

amount (8):
  Refund amount (fixed)

description (10):
  "Refund for order #12345"

paths (16):
  Merchant's blinded paths
  Merchant needs to receive buyer's invoice

refund_for (38): 32 bytes
  Original payment's payment_hash
  Links refund to original order

Example encoding:
lno1... (Offer containing send_invoice flag)

payer_key 的重要性

payer_key Enables Refundable Payments:

During Original Purchase:

Buyer sends invoice_request:
{
  offer_id: <Merchant's Offer ID>,
  payer_key: 0x02abc...def,  <- Buyer's public key
  payer_signature: <signature>
}

Merchant stores:
order_12345 = {
  payment_hash: 0x123...abc,
  payer_key: 0x02abc...def,  <- Remember buyer's public key
  amount: 100000 msat,
  timestamp: 1699999999
}

Using payer_key for Refund:

Merchant creates refund Offer:
{
  send_invoice: true,
  amount: 100000 msat,
  refund_for: 0x123...abc,
  payer_key: 0x02abc...def  <- Specify recipient
}

Only buyer with corresponding private key can:
  • Decrypt messages sent to that payer_key
  • Prove they are the original buyer
  • Provide valid payment invoice

實現細節

Merchant-side Refund Implementation:

Initiating Refund:

1. Query original order
   order = database.get_order(order_id)

2. Create refund Offer
   refund_offer = {
     send_invoice: true,
     amount: order.amount,
     description: f"Refund for {order_id}",
     refund_for: order.payment_hash,
     paths: generate_blinded_paths()
   }

3. Send to buyer
   send_onion_message(
     destination: order.payer_key,
     content: refund_offer
   )

4. Wait for buyer's invoice
   invoice = await receive_invoice()

5. Verify invoice
   verify(invoice.payer_key == order.payer_key)
   verify(invoice.amount == refund_offer.amount)

6. Pay invoice
   pay(invoice)

Buyer-side Processing:

1. Receive refund Offer
   offer = receive_onion_message()
   verify(offer.send_invoice == true)

2. Verify refund validity
   original_payment = database.get_payment(offer.refund_for)
   verify(original_payment exists)

3. Create payment invoice
   invoice = create_invoice(
     amount: offer.amount,
     payment_paths: generate_paths()
   )

4. Send invoice
   send_onion_message(
     destination: offer.paths[0],
     content: invoice
   )

5. Wait for payment
   await receive_payment()

安全考量

Refund Security Mechanisms:

Preventing Fraudulent Refunds:

1. payer_key Binding
   • Refund can only go to original buyer
   • Cannot impersonate buyer to request refund
   • Requires possession of corresponding private key

2. refund_for Association
   • Explicitly linked to original payment
   • Auditable refund records
   • Prevents duplicate refunds

3. Merchant Control
   • Merchant decides whether to refund
   • Merchant sets refund amount
   • Merchant verifies buyer identity

Buyer Protection:

Verify Refund Offer:
  • Confirm send_invoice = true
  • Confirm refund_for corresponds to real payment
  • Confirm amount is reasonable
  • Confirm source is trusted (via paths)

Precautions:
  • Don't provide invoices to unknown Offers
  • Verify merchant identity
  • Keep payment records

應用場景

電商退貨、服務取消、超額支付退回、 獎勵發放等商業場景。

vs LNURL-withdraw

BOLT12 退款是原生協議,不需要 HTTP 服務。 更好的隱私和可靠性。

在線需求: 買家需要在線才能接收退款 Offer 並提供發票。 離線買家可能錯過退款窗口。

相關資源

下一步: 了解 Invoice Request 的詳細協議流程。

已複製連結
已複製到剪貼簿