-
Notifications
You must be signed in to change notification settings - Fork 135
Expand file tree
/
Copy pathonchain.rs
More file actions
184 lines (166 loc) · 7.27 KB
/
onchain.rs
File metadata and controls
184 lines (166 loc) · 7.27 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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
// 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 crate::config::Config;
use crate::error::Error;
use crate::logger::{log_info, LdkLogger, Logger};
use crate::types::{ChannelManager, Wallet};
use crate::wallet::OnchainSendAmount;
use bitcoin::{Address, Txid};
use std::sync::{Arc, RwLock};
#[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
pub struct OnchainPayment {
runtime: Arc<RwLock<Option<Arc<tokio::runtime::Runtime>>>>,
wallet: Arc<Wallet>,
channel_manager: Arc<ChannelManager>,
config: Arc<Config>,
logger: Arc<Logger>,
}
impl OnchainPayment {
pub(crate) fn new(
runtime: Arc<RwLock<Option<Arc<tokio::runtime::Runtime>>>>, wallet: Arc<Wallet>,
channel_manager: Arc<ChannelManager>, config: Arc<Config>, logger: Arc<Logger>,
) -> Self {
Self { runtime, wallet, channel_manager, config, logger }
}
/// 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> {
let rt_lock = self.runtime.read().unwrap();
if rt_lock.is_none() {
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> {
let rt_lock = self.runtime.read().unwrap();
if rt_lock.is_none() {
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)
}
/// Estimates the fee for sending 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 for estimating 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 estimate_send_to_address(
&self, address: &Address, amount_sats: u64, fee_rate: Option<FeeRate>,
) -> Result<bitcoin::Amount, Error> {
let rt_lock = self.runtime.read().unwrap();
if rt_lock.is_none() {
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.estimate_fee(address, send_amount, fee_rate_opt)
}
/// Estimates the fee for sending 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 estimate_send_all_to_address(
&self, address: &Address, retain_reserves: bool, fee_rate: Option<FeeRate>,
) -> Result<bitcoin::Amount, Error> {
let rt_lock = self.runtime.read().unwrap();
if rt_lock.is_none() {
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.estimate_fee(address, send_amount, fee_rate_opt)
}
}