1
2use anyhow::Context;
3use bitcoin::FeeRate;
4use log::warn;
5
6use crate::Wallet;
7use crate::exit::{Exit, ExitProgressStatus};
8use crate::onchain::{CpfpError, MakeCpfpFees};
9
10pub (crate) fn should_rbf(new_fee_rate: FeeRate, old_fee_rate: FeeRate) -> bool {
13 new_fee_rate > old_fee_rate
14}
15
16impl Exit {
17 pub async fn progress_exits_with_cpfp(
34 &self,
35 wallet: &Wallet,
36 fee_rate_override: Option<FeeRate>,
37 ) -> anyhow::Result<Option<Vec<ExitProgressStatus>>> {
38 let onchain_arc = wallet.inner.onchain.as_ref()
39 .context("no onchain wallet configured; cannot progress exits")?;
40
41 self.progress_exits(wallet).await?;
42
43 let fee_rate = match fee_rate_override {
44 Some(fr) => fr,
45 None => wallet.exit_mgr().default_exit_fee_rate().await,
46 };
47
48 for req in self.exits_needing_cpfp().await {
49 let fees = match req.rbf_requirement {
50 None => MakeCpfpFees::Effective(fee_rate),
51 Some(rbf) => {
52 if !should_rbf(fee_rate, rbf.min_fee_rate) {
55 warn!(
56 "Skipping exit CPFP RBF: requested fee rate {} is not above current package rate {}",
57 fee_rate, rbf.min_fee_rate,
58 );
59 continue;
60 }
61 MakeCpfpFees::Rbf {
62 min_effective_fee_rate: fee_rate,
63 current_package_fee: rbf.current_package_fee,
64 }
65 },
66 };
67 let child_tx = {
68 let mut onchain = onchain_arc.write().await;
69 let tx = match onchain.make_signed_p2a_cpfp(&req.exit_tx, fees).await {
70 Ok(tx) => tx,
71 Err(CpfpError::InsufficientConfirmedFunds { needed, available }) => {
72 warn!("Insufficient funds for exit CPFP: needed {} available {}", needed, available);
73 continue;
74 },
75 Err(e) => return Err(e.into()),
76 };
77 onchain.store_signed_p2a_cpfp(&tx).await?;
78 tx
79 };
80 let exit_txid = req.exit_tx.compute_txid();
81 self.provide_cpfp_tx(wallet, exit_txid, child_tx).await?;
82 }
83
84 self.progress_exits(wallet).await
85 }
86}