Skip to content
This repository was archived by the owner on Feb 3, 2025. It is now read-only.

RBF fee bumping utilities #964

Merged
merged 1 commit into from
Jan 15, 2024
Merged
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
1 change: 1 addition & 0 deletions mutiny-core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ impl From<bdk::Error> for MutinyError {
match e {
bdk::Error::Signer(_) => Self::WalletSigningFailed,
bdk::Error::InsufficientFunds { .. } => Self::InsufficientBalance,
bdk::Error::TransactionNotFound => Self::NotFound,
_ => Self::WalletOperationFailed,
}
}
Expand Down
23 changes: 20 additions & 3 deletions mutiny-core/src/nodemanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ use payjoin::{PjUri, PjUriExt};
use reqwest::Client;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::cmp::max;
use std::io::Cursor;
use std::str::FromStr;
use std::sync::atomic::{AtomicBool, Ordering};
Expand Down Expand Up @@ -935,6 +936,22 @@ impl<S: MutinyStorage> NodeManager<S> {
self.wallet.estimate_sweep_tx_fee(script, fee_rate)
}

/// Bumps the given transaction by replacing the given tx with a transaction at
/// the new given fee rate in sats/vbyte
pub async fn bump_fee(&self, txid: Txid, new_fee_rate: f32) -> Result<Txid, MutinyError> {
// check that this is not a funding tx for any channels,
// bumping those can cause loss of funds
let channels = self.list_channels().await?;
if channels
.iter()
.any(|c| c.outpoint.is_some_and(|t| t.txid == txid))
{
return Err(MutinyError::ChannelCreationFailed);
}

self.wallet.bump_fee(txid, new_fee_rate).await
}

/// Checks if the given address has any transactions.
/// If it does, it returns the details of the first transaction.
///
Expand Down Expand Up @@ -1312,19 +1329,19 @@ impl<S: MutinyStorage> NodeManager<S> {
/// Gets a fee estimate for a very low priority transaction.
/// Value is in sat/vbyte.
pub fn estimate_fee_low(&self) -> u32 {
self.fee_estimator.get_low_fee_rate() / 250
max(self.fee_estimator.get_low_fee_rate() / 250, 1)
}

/// Gets a fee estimate for an average priority transaction.
/// Value is in sat/vbyte.
pub fn estimate_fee_normal(&self) -> u32 {
self.fee_estimator.get_normal_fee_rate() / 250
max(self.fee_estimator.get_normal_fee_rate() / 250, 1)
}

/// Gets a fee estimate for an high priority transaction.
/// Value is in sat/vbyte.
pub fn estimate_fee_high(&self) -> u32 {
self.fee_estimator.get_high_fee_rate() / 250
max(self.fee_estimator.get_high_fee_rate() / 250, 1)
}

/// Creates a new lightning node and adds it to the manager.
Expand Down
21 changes: 21 additions & 0 deletions mutiny-core/src/onchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,27 @@ impl<S: MutinyStorage> OnChainWallet<S> {

psbt.fee_amount().ok_or(MutinyError::WalletOperationFailed)
}

/// Bumps the given transaction by replacing the given tx with a transaction at
/// the new given fee rate in sats/vbyte
pub async fn bump_fee(&self, txid: Txid, new_fee_rate: f32) -> Result<Txid, MutinyError> {
let tx = {
let mut wallet = self.wallet.try_write()?;
// build RBF fee bump tx
let mut builder = wallet.build_fee_bump(txid)?;
builder.fee_rate(FeeRate::from_sat_per_vb(new_fee_rate));
let (mut psbt, _) = builder.finish()?;
wallet.sign(&mut psbt, SignOptions::default())?;

psbt.extract_tx()
};

let txid = tx.txid();

self.broadcast_transaction(tx).await?;
log_debug!(self.logger, "Fee bump Transaction broadcast! TXID: {txid}");
Ok(txid)
}
}

fn get_tr_descriptors_for_extended_key(
Expand Down
16 changes: 16 additions & 0 deletions mutiny-wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,15 @@ impl MutinyWallet {
.estimate_sweep_channel_open_fee(fee_rate)?)
}

/// Bumps the given transaction by replacing the given tx with a transaction at
/// the new given fee rate in sats/vbyte
pub async fn bump_fee(&self, txid: String, fee_rate: f32) -> Result<String, MutinyJsError> {
let txid = Txid::from_str(&txid)?;
let result = self.inner.node_manager.bump_fee(txid, fee_rate).await?;

Ok(result.to_string())
}

/// Checks if the given address has any transactions.
/// If it does, it returns the details of the first transaction.
///
Expand Down Expand Up @@ -625,6 +634,13 @@ impl MutinyWallet {
Ok(JsValue::from_serde(&self.inner.node_manager.list_utxos()?)?)
}

/// Gets a fee estimate for an low priority transaction.
/// Value is in sat/vbyte.
#[wasm_bindgen]
pub fn estimate_fee_low(&self) -> u32 {
self.inner.node_manager.estimate_fee_low()
}

/// Gets a fee estimate for an average priority transaction.
/// Value is in sat/vbyte.
#[wasm_bindgen]
Expand Down