Skip to content

Commit 333d265

Browse files
committed
Add bumpfee rpc
1 parent ede8097 commit 333d265

File tree

2 files changed

+106
-1
lines changed

2 files changed

+106
-1
lines changed

client/src/client.rs

+13
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,19 @@ pub trait RpcApi: Sized {
269269
self.call("addmultisigaddress", handle_defaults(&mut args, &[into_json("")?, null()])).await
270270
}
271271

272+
async fn bump_fee(
273+
&self,
274+
txid: &bitcoin::Txid,
275+
options: Option<&json::BumpFeeOptions>,
276+
) -> Result<json::BumpFeeResult> {
277+
let opts = match options {
278+
Some(options) => Some(options.to_serializable(self.version().await?)),
279+
None => None,
280+
};
281+
let mut args = [into_json(txid)?, opt_into_json(opts)?];
282+
self.call("bumpfee", handle_defaults(&mut args, &[null()])).await
283+
}
284+
272285
async fn load_wallet(&self, wallet: &str) -> Result<json::LoadWalletResult> {
273286
self.call("loadwallet", &[wallet.into()]).await
274287
}

json/src/lib.rs

+93-1
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,38 @@ use bitcoin::{
3636
use serde::de::Error as SerdeError;
3737
use serde::{Deserialize, Serialize};
3838
use std::fmt;
39-
4039
//TODO(stevenroose) consider using a Time type
4140

41+
/// A representation of a fee rate. Bitcoin Core uses different units in different
42+
/// versions. To avoid burdening the user with using the correct unit, this struct
43+
/// provides an umambiguous way to represent the fee rate, and the lib will perform
44+
/// the necessary conversions.
45+
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
46+
pub struct FeeRate(Amount);
47+
48+
impl FeeRate {
49+
/// Construct FeeRate from the amount per vbyte
50+
pub fn per_vbyte(amount_per_vbyte: Amount) -> Self {
51+
// internal representation is amount per vbyte
52+
Self(amount_per_vbyte)
53+
}
54+
55+
/// Construct FeeRate from the amount per kilo-vbyte
56+
pub fn per_kvbyte(amount_per_kvbyte: Amount) -> Self {
57+
// internal representation is amount per vbyte, so divide by 1000
58+
Self::per_vbyte(amount_per_kvbyte / 1000)
59+
}
60+
61+
pub fn to_sat_per_vbyte(&self) -> f64 {
62+
// multiply by the number of decimals to get sat
63+
self.0.to_sat() as f64
64+
}
65+
66+
pub fn to_btc_per_kvbyte(&self) -> f64 {
67+
// divide by 10^8 to get btc/vbyte, then multiply by 10^3 to get btc/kbyte
68+
self.0.to_sat() as f64 / 100_000.0
69+
}
70+
}
4271
/// A module used for serde serialization of bytes in hexadecimal format.
4372
///
4473
/// The module is compatible with the serde attribute.
@@ -1985,6 +2014,69 @@ pub struct FundRawTransactionResult {
19852014
pub change_position: i32,
19862015
}
19872016

2017+
#[derive(Clone, PartialEq, Eq, Debug, Default)]
2018+
pub struct BumpFeeOptions {
2019+
/// Confirmation target in blocks.
2020+
pub conf_target: Option<u16>,
2021+
/// Specify a fee rate instead of relying on the built-in fee estimator.
2022+
pub fee_rate: Option<FeeRate>,
2023+
/// Whether this transaction could be replaced due to BIP125 (replace-by-fee)
2024+
pub replaceable: Option<bool>,
2025+
/// The fee estimate mode
2026+
pub estimate_mode: Option<EstimateMode>,
2027+
}
2028+
2029+
impl BumpFeeOptions {
2030+
pub fn to_serializable(&self, version: usize) -> SerializableBumpFeeOptions {
2031+
let fee_rate = self.fee_rate.map(|x| {
2032+
if version < 210000 {
2033+
x.to_btc_per_kvbyte()
2034+
} else {
2035+
x.to_sat_per_vbyte()
2036+
}
2037+
});
2038+
2039+
SerializableBumpFeeOptions {
2040+
fee_rate,
2041+
conf_target: self.conf_target,
2042+
replaceable: self.replaceable,
2043+
estimate_mode: self.estimate_mode,
2044+
}
2045+
}
2046+
}
2047+
2048+
#[derive(Serialize, Clone, PartialEq, Debug, Default)]
2049+
#[serde(rename_all = "camelCase")]
2050+
pub struct SerializableBumpFeeOptions {
2051+
#[serde(rename = "conf_target", skip_serializing_if = "Option::is_none")]
2052+
/// Confirmation target in blocks.
2053+
pub conf_target: Option<u16>,
2054+
/// Specify a fee rate instead of relying on the built-in fee estimator.
2055+
#[serde(rename = "fee_rate")]
2056+
pub fee_rate: Option<f64>,
2057+
/// Whether this transaction could be replaced due to BIP125 (replace-by-fee)
2058+
#[serde(skip_serializing_if = "Option::is_none")]
2059+
pub replaceable: Option<bool>,
2060+
/// The fee estimate mode
2061+
#[serde(rename = "estimate_mode", skip_serializing_if = "Option::is_none")]
2062+
pub estimate_mode: Option<EstimateMode>,
2063+
}
2064+
2065+
#[derive(Deserialize, Clone, PartialEq, Eq, Debug)]
2066+
#[serde(rename_all = "camelCase")]
2067+
pub struct BumpFeeResult {
2068+
/// The base64-encoded unsigned PSBT of the new transaction. Only returned when wallet private keys are disabled.
2069+
pub psbt: Option<String>,
2070+
/// The id of the new transaction. Only returned when wallet private keys are enabled.
2071+
pub txid: Option<bitcoin::Txid>,
2072+
#[serde(with = "bitcoin::amount::serde::as_btc")]
2073+
pub origfee: Amount,
2074+
#[serde(with = "bitcoin::amount::serde::as_btc")]
2075+
pub fee: Amount,
2076+
/// Errors encountered during processing.
2077+
pub errors: Vec<String>,
2078+
}
2079+
19882080
#[derive(Deserialize, Clone, PartialEq, Eq, Debug)]
19892081
pub struct GetBalancesResultEntry {
19902082
#[serde(with = "bitcoin::amount::serde::as_btc")]

0 commit comments

Comments
 (0)