-
Notifications
You must be signed in to change notification settings - Fork 158
Expand file tree
/
Copy pathonchain.rs
More file actions
167 lines (151 loc) · 6.5 KB
/
Copy pathonchain.rs
File metadata and controls
167 lines (151 loc) · 6.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// This file is Copyright its original authors, visible in version control history.
//
// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. You may not use this file except in
// accordance with one or both of these licenses.
//! Holds a payment handler allowing to send and receive on-chain payments.
use std::sync::{Arc, RwLock};
use bitcoin::{Address, Txid};
use lightning::ln::channelmanager::PaymentId;
use crate::config::Config;
use crate::error::Error;
use crate::logger::{log_info, LdkLogger, Logger};
use crate::types::{ChannelManager, Wallet};
use crate::wallet::OnchainSendAmount;
#[cfg(not(feature = "uniffi"))]
type FeeRate = bitcoin::FeeRate;
#[cfg(feature = "uniffi")]
type FeeRate = Arc<bitcoin::FeeRate>;
macro_rules! maybe_map_fee_rate_opt {
($fee_rate_opt:expr) => {{
#[cfg(not(feature = "uniffi"))]
{
$fee_rate_opt
}
#[cfg(feature = "uniffi")]
{
$fee_rate_opt.map(|f| *f)
}
}};
}
/// A payment handler allowing to send and receive on-chain payments.
///
/// Should be retrieved by calling [`Node::onchain_payment`].
///
/// [`Node::onchain_payment`]: crate::Node::onchain_payment
#[cfg_attr(feature = "uniffi", derive(uniffi::Object))]
pub struct OnchainPayment {
wallet: Arc<Wallet>,
channel_manager: Arc<ChannelManager>,
config: Arc<Config>,
is_running: Arc<RwLock<bool>>,
logger: Arc<Logger>,
}
impl OnchainPayment {
pub(crate) fn new(
wallet: Arc<Wallet>, channel_manager: Arc<ChannelManager>, config: Arc<Config>,
is_running: Arc<RwLock<bool>>, logger: Arc<Logger>,
) -> Self {
Self { wallet, channel_manager, config, is_running, logger }
}
}
#[cfg_attr(feature = "uniffi", uniffi::export)]
impl OnchainPayment {
/// Retrieve a new on-chain/funding address.
pub fn new_address(&self) -> Result<Address, Error> {
let funding_address = self.wallet.get_new_address()?;
log_info!(self.logger, "Generated new funding address: {}", funding_address);
Ok(funding_address)
}
/// Send an on-chain payment to the given address.
///
/// This will respect any on-chain reserve we need to keep, i.e., won't allow to cut into
/// [`BalanceDetails::total_anchor_channels_reserve_sats`].
///
/// If `fee_rate` is set it will be used on the resulting transaction. Otherwise we'll retrieve
/// a reasonable estimate from the configured chain source.
///
/// [`BalanceDetails::total_anchor_channels_reserve_sats`]: crate::BalanceDetails::total_anchor_channels_reserve_sats
pub fn send_to_address(
&self, address: &bitcoin::Address, amount_sats: u64, fee_rate: Option<FeeRate>,
) -> Result<Txid, Error> {
if !*self.is_running.read().unwrap() {
return Err(Error::NotRunning);
}
let cur_anchor_reserve_sats =
crate::total_anchor_channels_reserve_sats(&self.channel_manager, &self.config);
let send_amount =
OnchainSendAmount::ExactRetainingReserve { amount_sats, cur_anchor_reserve_sats };
let fee_rate_opt = maybe_map_fee_rate_opt!(fee_rate);
self.wallet.send_to_address(address, send_amount, fee_rate_opt)
}
/// Send an on-chain payment to the given address, draining the available funds.
///
/// This is useful if you have closed all channels and want to migrate funds to another
/// on-chain wallet.
///
/// Please note that if `retain_reserves` is set to `false` this will **not** retain any on-chain reserves, which might be potentially
/// dangerous if you have open Anchor channels for which you can't trust the counterparty to
/// spend the Anchor output after channel closure. If `retain_reserves` is set to `true`, this
/// will try to send all spendable onchain funds, i.e.,
/// [`BalanceDetails::spendable_onchain_balance_sats`].
///
/// If `fee_rate` is set it will be used on the resulting transaction. Otherwise a reasonable
/// we'll retrieve an estimate from the configured chain source.
///
/// [`BalanceDetails::spendable_onchain_balance_sats`]: crate::balance::BalanceDetails::spendable_onchain_balance_sats
pub fn send_all_to_address(
&self, address: &bitcoin::Address, retain_reserves: bool, fee_rate: Option<FeeRate>,
) -> Result<Txid, Error> {
if !*self.is_running.read().unwrap() {
return Err(Error::NotRunning);
}
let send_amount = if retain_reserves {
let cur_anchor_reserve_sats =
crate::total_anchor_channels_reserve_sats(&self.channel_manager, &self.config);
OnchainSendAmount::AllRetainingReserve { cur_anchor_reserve_sats }
} else {
OnchainSendAmount::AllDrainingReserve
};
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 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)
}
/// Bumps the fee of a given UTXO using Child-Pays-For-Parent (CPFP) by creating a new transaction.
///
/// This method creates a new transaction that spends the specified UTXO with a higher fee rate,
/// effectively increasing the priority of both the new transaction and the parent transaction
/// it depends on. This is useful when a transaction is stuck in the mempool due to insufficient
/// fees and you want to accelerate its confirmation.
///
/// CPFP works by creating a child transaction that spends one or more outputs from the parent
/// transaction. Miners will consider the combined fees of both transactions when deciding
/// which transactions to include in a block.
///
/// # Parameters
/// * `payment_id` - The identifier of the payment whose UTXO should be fee-bumped
/// * `fee_rate` - The fee rate to use for the CPFP transaction, if not provided, a reasonable fee rate is used
///
/// Returns the [`Txid`] of the newly created CPFP transaction if successful.
pub fn bump_fee_cpfp(
&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_cpfp(payment_id, fee_rate_opt)
}
}