Skip to content
Open
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
2 changes: 2 additions & 0 deletions bindings/ldk_node.udl
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,8 @@ interface OnchainPayment {
Txid send_to_address([ByRef]Address address, u64 amount_sats, FeeRate? fee_rate);
[Throws=NodeError]
Txid send_all_to_address([ByRef]Address address, boolean retain_reserve, FeeRate? fee_rate);
[Throws=NodeError]
Txid bump_fee_rbf(PaymentId payment_id, FeeRate? fee_rate);
};

interface FeeRate {
Expand Down
18 changes: 18 additions & 0 deletions src/payment/onchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use std::sync::{Arc, RwLock};

use bitcoin::{Address, Txid};
use lightning::ln::channelmanager::PaymentId;

use crate::config::Config;
use crate::error::Error;
Expand Down Expand Up @@ -120,4 +121,21 @@ impl OnchainPayment {
let fee_rate_opt = maybe_map_fee_rate_opt!(fee_rate);
self.wallet.send_to_address(address, send_amount, fee_rate_opt)
}

/// Attempt to bump the fee of an unconfirmed transaction using Replace-by-Fee (RBF).
///
/// This creates a new transaction that replaces the original one, increasing the fee by the
/// specified increment to improve its chances of confirmation. The original transaction must
/// be signaling RBF replaceability for this to succeed.
///
/// The new transaction will have the same outputs as the original but with a
/// higher fee, resulting in faster confirmation potential.
///
/// Returns the Txid of the new replacement transaction if successful.
pub fn bump_fee_rbf(
&self, payment_id: PaymentId, fee_rate: Option<FeeRate>,
) -> Result<Txid, Error> {
let fee_rate_opt = maybe_map_fee_rate_opt!(fee_rate);
self.wallet.bump_fee_rbf(payment_id, fee_rate_opt)
}
}
11 changes: 6 additions & 5 deletions src/payment/pending_payment_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,11 @@ impl StorableObjectUpdate<PendingPaymentDetails> for PendingPaymentDetailsUpdate

impl From<&PendingPaymentDetails> for PendingPaymentDetailsUpdate {
fn from(value: &PendingPaymentDetails) -> Self {
Self {
id: value.id(),
payment_update: Some(value.details.to_update()),
conflicting_txids: Some(value.conflicting_txids.clone()),
}
let conflicting_txids = if value.conflicting_txids.is_empty() {
None
} else {
Some(value.conflicting_txids.clone())
};
Self { id: value.id(), payment_update: Some(value.details.to_update()), conflicting_txids }
}
}
18 changes: 15 additions & 3 deletions src/payment/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,15 @@ impl StorableObject for PaymentDetails {
}
}

if let Some(tx_id) = update.txid {
match self.kind {
PaymentKind::Onchain { ref mut txid, .. } => {
update_if_necessary!(*txid, tx_id);
},
_ => {},
}
}

if updated {
self.latest_update_timestamp = SystemTime::now()
.duration_since(UNIX_EPOCH)
Expand Down Expand Up @@ -540,6 +549,7 @@ pub(crate) struct PaymentDetailsUpdate {
pub direction: Option<PaymentDirection>,
pub status: Option<PaymentStatus>,
pub confirmation_status: Option<ConfirmationStatus>,
pub txid: Option<Txid>,
}

impl PaymentDetailsUpdate {
Expand All @@ -555,6 +565,7 @@ impl PaymentDetailsUpdate {
direction: None,
status: None,
confirmation_status: None,
txid: None,
}
}
}
Expand All @@ -570,9 +581,9 @@ impl From<&PaymentDetails> for PaymentDetailsUpdate {
_ => (None, None, None),
};

let confirmation_status = match value.kind {
PaymentKind::Onchain { status, .. } => Some(status),
_ => None,
let (confirmation_status, txid) = match &value.kind {
PaymentKind::Onchain { status, txid, .. } => (Some(*status), Some(*txid)),
_ => (None, None),
};

let counterparty_skimmed_fee_msat = match value.kind {
Expand All @@ -593,6 +604,7 @@ impl From<&PaymentDetails> for PaymentDetailsUpdate {
direction: Some(value.direction),
status: Some(value.status),
confirmation_status,
txid,
}
}
}
Expand Down
Loading
Loading