diff --git a/index.d.ts b/index.d.ts index 1b3dbcf..1466554 100644 --- a/index.d.ts +++ b/index.d.ts @@ -39,6 +39,7 @@ export interface MdkNodeOptions { scoringParamOverrides?: ScoringParamOverrides splice?: SpliceConfig maxSendable?: MaxSendableConfig + feeClaim?: string } /** * Configuration for the auto-splice manager. The manager wakes up every @@ -155,6 +156,7 @@ export declare class MdkNode { * * If `splice.enabled` is set on construction (the default), also spawns * the auto-splice background task on the dedicated splice runtime. + * Start the node. Call once before polling for events. */ startReceiving(): void /** @@ -188,10 +190,7 @@ export declare class MdkNode { * Lightning right now, with routing-fee headroom subtracted. * * When `destination` is supplied, the fee budget comes from a real - * `find_route` against that destination (currently zero-amount BOLT11 - * only). BOLT12, LNURL-pay, and HRN destinations parse but fall back - * to the destination-agnostic buffer until invoice/HRN resolution - * moves into the estimator. + * `find_route` against that destination. * * Returns `null` when no usable LSP channel exists. `Some(amountMsat: 0)` * is distinct from `null` — it means a channel exists but the balance @@ -203,8 +202,6 @@ export declare class MdkNode { * Throws `InvalidArg` when the destination cannot be parsed, dictates * its own amount (fixed-amount BOLT11/BOLT12), or carries no Lightning * method. Throws `GenericFailure` when routing fails outright. - * - * Read-only; safe to call whether or not the node has been started. */ getMaxSendable(destination?: string | undefined | null): MaxSendableEstimate | null /** diff --git a/src/lib.rs b/src/lib.rs index 2d9fca1..c850f1d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -303,6 +303,7 @@ pub struct MdkNodeOptions { pub scoring_param_overrides: Option, pub splice: Option, pub max_sendable: Option, + pub fee_claim: Option, } /// Configuration for the auto-splice manager. The manager wakes up every @@ -513,9 +514,7 @@ impl MdkNode { let logger_arc = Arc::clone(logger_instance()); let logger: Arc = logger_arc; builder.set_custom_logger(logger); - // Third arg is the optional LSPS4 fee_claim (added in ldk-node #37). None - // preserves prior behavior (no fee claim configured). - builder.set_liquidity_source_lsps4(lsp_node_id, lsp_address, None); + builder.set_liquidity_source_lsps4(lsp_node_id, lsp_address, options.fee_claim.clone()); if let Some(scoring) = options.scoring_param_overrides { let mut fee_params = ProbabilisticScoringFeeParameters::default(); @@ -719,95 +718,87 @@ impl MdkNode { #[napi] pub fn next_event(&self) -> Option { loop { - match self.node().next_event() { - Some(event) => { - let payment_event = match &event { - Event::PaymentClaimable { - payment_hash, - claimable_amount_msat, - .. - } => Some(PaymentEvent { - event_type: PaymentEventType::Claimable, - payment_hash: bytes_to_hex(&payment_hash.0), - amount_msat: Some(*claimable_amount_msat as i64), - reason: None, - payer_note: None, - payment_id: None, - preimage: None, - }), - Event::PaymentReceived { - payment_id, - payment_hash, - amount_msat, - .. - } => { - let payer_note = payment_id.and_then(|pid| { - self - .node() - .payment(&pid) - .and_then(|details| match details.kind { - PaymentKind::Bolt12Offer { payer_note, .. } => { - payer_note.map(|n| n.to_string()) - } - PaymentKind::Bolt12Refund { payer_note, .. } => { - payer_note.map(|n| n.to_string()) - } - _ => None, - }) - }); - Some(PaymentEvent { - event_type: PaymentEventType::Received, - payment_hash: bytes_to_hex(&payment_hash.0), - amount_msat: Some(*amount_msat as i64), - reason: None, - payer_note, - payment_id: None, - preimage: None, + let event = self.node().next_event()?; + let payment_event = match &event { + Event::PaymentClaimable { + payment_hash, + claimable_amount_msat, + .. + } => Some(PaymentEvent { + event_type: PaymentEventType::Claimable, + payment_hash: bytes_to_hex(&payment_hash.0), + amount_msat: Some(*claimable_amount_msat as i64), + reason: None, + payer_note: None, + payment_id: None, + preimage: None, + }), + Event::PaymentReceived { + payment_id, + payment_hash, + amount_msat, + .. + } => { + let payer_note = payment_id.and_then(|pid| { + self + .node() + .payment(&pid) + .and_then(|details| match details.kind { + PaymentKind::Bolt12Offer { payer_note, .. } => payer_note.map(|n| n.to_string()), + PaymentKind::Bolt12Refund { payer_note, .. } => payer_note.map(|n| n.to_string()), + _ => None, }) - } - Event::PaymentFailed { - payment_id: event_pid, - payment_hash, - reason, - .. - } => payment_hash.map(|h| PaymentEvent { - event_type: PaymentEventType::Failed, - payment_hash: bytes_to_hex(&h.0), - amount_msat: None, - reason: reason.map(|r| format!("{r:?}")), - payer_note: None, - payment_id: event_pid.map(|id| bytes_to_hex(&id.0)), - preimage: None, - }), - Event::PaymentSuccessful { - payment_id: event_pid, - payment_hash, - payment_preimage, - .. - } => Some(PaymentEvent { - event_type: PaymentEventType::Sent, - payment_hash: bytes_to_hex(&payment_hash.0), - amount_msat: None, - reason: None, - payer_note: None, - payment_id: event_pid.map(|id| bytes_to_hex(&id.0)), - preimage: payment_preimage.map(|p| bytes_to_hex(&p.0)), - }), - _ => None, - }; - - // If this is a payment event we care about, return it (without ACKing) - if payment_event.is_some() { - return payment_event; - } - - // For non-payment events, ACK and continue to next event - // Potentially problematic if a payout is happening at the same time - // but this is the existing behavior. - let _ = self.node().event_handled(); + }); + Some(PaymentEvent { + event_type: PaymentEventType::Received, + payment_hash: bytes_to_hex(&payment_hash.0), + amount_msat: Some(*amount_msat as i64), + reason: None, + payer_note, + payment_id: None, + preimage: None, + }) } - None => return None, + Event::PaymentFailed { + payment_id: event_pid, + payment_hash, + reason, + .. + } => payment_hash.map(|h| PaymentEvent { + event_type: PaymentEventType::Failed, + payment_hash: bytes_to_hex(&h.0), + amount_msat: None, + reason: reason.map(|r| format!("{r:?}")), + payer_note: None, + payment_id: event_pid.map(|id| bytes_to_hex(&id.0)), + preimage: None, + }), + Event::PaymentSuccessful { + payment_id: event_pid, + payment_hash, + payment_preimage, + .. + } => Some(PaymentEvent { + event_type: PaymentEventType::Sent, + payment_hash: bytes_to_hex(&payment_hash.0), + amount_msat: None, + reason: None, + payer_note: None, + payment_id: event_pid.map(|id| bytes_to_hex(&id.0)), + preimage: payment_preimage.map(|p| bytes_to_hex(&p.0)), + }), + _ => None, + }; + + // If this is a payment event we care about, return it (without ACKing) + if payment_event.is_some() { + return payment_event; } + + // For non-payment events, ACK and continue to next event + // Potentially problematic if a payout is happening at the same time + // but this is the existing behavior. + let _ = self.node().event_handled(); } }