|
| 1 | +# Receiving Payments |
| 2 | + |
| 3 | +To receive a payment, you'll need to create an invoice of your own with an |
| 4 | +amount and description. `ChannelManager` contains the remaining information |
| 5 | +needed for the invoice. Use the provided utility to generate an invoice and |
| 6 | +register a pending payment in `ChannelManager`. |
| 7 | + |
| 8 | +<CodeSwitcher :languages="{rust:'Rust', kotlin:'Kotlin', swift: 'Swift'}"> |
| 9 | + <template v-slot:rust> |
| 10 | + |
| 11 | +```rust |
| 12 | +let invoice = match utils::create_invoice_from_channelmanager( |
| 13 | + channel_manager, |
| 14 | + keys_manager, |
| 15 | + logger, |
| 16 | + currency, |
| 17 | + Some(amt_msat), |
| 18 | + "description".to_string(), |
| 19 | + expiry_secs, |
| 20 | + None, |
| 21 | +) { |
| 22 | + Ok(inv) => { |
| 23 | + println!("SUCCESS: generated invoice: {}", inv); |
| 24 | + inv |
| 25 | + } |
| 26 | + Err(e) => { |
| 27 | + println!("ERROR: failed to create invoice: {:?}", e); |
| 28 | + return; |
| 29 | + } |
| 30 | +}; |
| 31 | + |
| 32 | +let payment_hash = PaymentHash(invoice.payment_hash().to_byte_array()); |
| 33 | +inbound_payments.payments.insert( |
| 34 | + payment_hash, |
| 35 | + PaymentInfo { |
| 36 | + preimage: None, |
| 37 | + secret: Some(invoice.payment_secret().clone()), |
| 38 | + status: HTLCStatus::Pending, |
| 39 | + amt_msat: MillisatAmount(Some(amt_msat)), |
| 40 | + }, |
| 41 | +); |
| 42 | + |
| 43 | +``` |
| 44 | + |
| 45 | + </template> |
| 46 | + <template v-slot:kotlin> |
| 47 | + |
| 48 | +```kotlin |
| 49 | +val description = "description" |
| 50 | +val amtMsat: Long = 3000000 |
| 51 | +val invoice = UtilMethods.create_invoice_from_channelmanager( |
| 52 | + channelManager, |
| 53 | + keysManager.inner.as_NodeSigner(), |
| 54 | + logger, |
| 55 | + Currency.LDKCurrency_Regtest, |
| 56 | + Option_u64Z.some(amtMsat), |
| 57 | + description, |
| 58 | + 300, |
| 59 | + Option_u16Z.some(144) |
| 60 | +) |
| 61 | + |
| 62 | +val invoiceResult = (invoice as Result_Bolt11InvoiceSignOrCreationErrorZ.Result_Bolt11InvoiceSignOrCreationErrorZ_OK).res |
| 63 | +val encodedInvoice = invoiceResult.to_str() |
| 64 | +``` |
| 65 | + |
| 66 | + </template> |
| 67 | + |
| 68 | + <template v-slot:swift> |
| 69 | + |
| 70 | +```swift |
| 71 | +let invoice = Bindings.createInvoiceFromChannelmanager( |
| 72 | + channelmanager: self.channelManager!, |
| 73 | + nodeSigner: myKeysManager.inner.asNodeSigner(), |
| 74 | + logger: self.logger, |
| 75 | + network: currency, |
| 76 | + amtMsat: amount, |
| 77 | + description: "Test Invoice", |
| 78 | + invoiceExpiryDeltaSecs: expiry, |
| 79 | + minFinalCltvExpiryDelta: nil |
| 80 | +) |
| 81 | + |
| 82 | +invoice.getValue()!.toStr() |
| 83 | +``` |
| 84 | + |
| 85 | + </template> |
| 86 | +</CodeSwitcher> |
| 87 | + |
| 88 | +While it is possible to create an invoice without using the utility, |
| 89 | +`ChannelManager` will reject any incoming HTLCs for unregistered payments to |
| 90 | +protect your privacy. In this case, use either `create_inbound_payment` or |
| 91 | +`create_inbound_payment_for_hash` to register a payment with `ChannelManager` |
| 92 | +before creating the invoice with the returned payment hash and/or secret. |
| 93 | +You might also opt to for `inbound_payment`, useful for generating invoices for [phantom node payments](https://docs.rs/lightning/*/lightning/sign/struct.PhantomKeysManager.html) without a ChannelManager. |
| 94 | + |
| 95 | +# PaymentClaimable Event Handling |
| 96 | + |
| 97 | +As with sending a payment, LDK will generate an event once a payment is |
| 98 | +received. It is your responsibility to handle the `PaymentClaimable` event by |
| 99 | +using `ChannelManager` to release the preimage and claim the funds. |
| 100 | + |
| 101 | +<CodeSwitcher :languages="{rust:'Rust', kotlin:'Kotlin', swift:'Swift'}"> |
| 102 | + <template v-slot:rust> |
| 103 | + |
| 104 | +```rust |
| 105 | +Event::PaymentClaimable { |
| 106 | + payment_hash, |
| 107 | + purpose, |
| 108 | + amount_msat, |
| 109 | + receiver_node_id: _, |
| 110 | + via_channel_id: _, |
| 111 | + via_user_channel_id: _, |
| 112 | + claim_deadline: _, |
| 113 | + onion_fields: _, |
| 114 | + counterparty_skimmed_fee_msat: _, |
| 115 | +} => { |
| 116 | + println!( |
| 117 | + "\nEVENT: received payment from payment hash {} of {} millisatoshis", |
| 118 | + payment_hash, amount_msat, |
| 119 | + ); |
| 120 | + print!("> "); |
| 121 | + io::stdout().flush().unwrap(); |
| 122 | + let payment_preimage = match purpose { |
| 123 | + PaymentPurpose::InvoicePayment { payment_preimage, .. } => payment_preimage, |
| 124 | + PaymentPurpose::SpontaneousPayment(preimage) => Some(preimage), |
| 125 | + }; |
| 126 | + channel_manager.claim_funds(payment_preimage.unwrap()); |
| 127 | +} |
| 128 | +``` |
| 129 | + |
| 130 | + </template> |
| 131 | + <template v-slot:kotlin> |
| 132 | + |
| 133 | +```kotlin |
| 134 | +if (event is Event.PaymentClaimable) { |
| 135 | + if (event.payment_hash != null) { |
| 136 | + val purpose = event.purpose as InvoicePayment |
| 137 | + val paymentPreimage = (purpose.payment_preimage as Option_ThirtyTwoBytesZ.Some).some |
| 138 | + |
| 139 | + channelManager.claim_funds(paymentPreimage) |
| 140 | + } |
| 141 | +} |
| 142 | +``` |
| 143 | + |
| 144 | + </template> |
| 145 | + |
| 146 | + <template v-slot:swift> |
| 147 | + |
| 148 | +```swift |
| 149 | +if let paymentClaimedEvent = event.getValueAsPaymentClaimable() { |
| 150 | + let paymentPreimage = paymentClaimedEvent.getPurpose().getValueAsInvoicePayment()?.getPaymentPreimage() |
| 151 | + let _ = channelManager.claimFunds(paymentPreimage: paymentPreimage!) |
| 152 | +} |
| 153 | +``` |
| 154 | + |
| 155 | + </template> |
| 156 | +</CodeSwitcher> |
| 157 | + |
| 158 | +**References:** [Rust `PaymentClaimable` docs](https://docs.rs/lightning/*/lightning/events/enum.Event.html#variant.PaymentClaimable), [Java/Kotlin `PaymentClaimable` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Event.java#L261) |
0 commit comments