Skip to content

Commit

Permalink
Add bumpfee rpc
Browse files Browse the repository at this point in the history
  • Loading branch information
jfldde committed Oct 18, 2024
1 parent ede8097 commit 333d265
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 1 deletion.
13 changes: 13 additions & 0 deletions client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,19 @@ pub trait RpcApi: Sized {
self.call("addmultisigaddress", handle_defaults(&mut args, &[into_json("")?, null()])).await
}

async fn bump_fee(
&self,
txid: &bitcoin::Txid,
options: Option<&json::BumpFeeOptions>,
) -> Result<json::BumpFeeResult> {
let opts = match options {
Some(options) => Some(options.to_serializable(self.version().await?)),
None => None,
};
let mut args = [into_json(txid)?, opt_into_json(opts)?];
self.call("bumpfee", handle_defaults(&mut args, &[null()])).await
}

async fn load_wallet(&self, wallet: &str) -> Result<json::LoadWalletResult> {
self.call("loadwallet", &[wallet.into()]).await
}
Expand Down
94 changes: 93 additions & 1 deletion json/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,38 @@ use bitcoin::{
use serde::de::Error as SerdeError;
use serde::{Deserialize, Serialize};
use std::fmt;

//TODO(stevenroose) consider using a Time type

/// A representation of a fee rate. Bitcoin Core uses different units in different
/// versions. To avoid burdening the user with using the correct unit, this struct
/// provides an umambiguous way to represent the fee rate, and the lib will perform
/// the necessary conversions.
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
pub struct FeeRate(Amount);

impl FeeRate {
/// Construct FeeRate from the amount per vbyte
pub fn per_vbyte(amount_per_vbyte: Amount) -> Self {
// internal representation is amount per vbyte
Self(amount_per_vbyte)
}

/// Construct FeeRate from the amount per kilo-vbyte
pub fn per_kvbyte(amount_per_kvbyte: Amount) -> Self {
// internal representation is amount per vbyte, so divide by 1000
Self::per_vbyte(amount_per_kvbyte / 1000)
}

pub fn to_sat_per_vbyte(&self) -> f64 {
// multiply by the number of decimals to get sat
self.0.to_sat() as f64
}

pub fn to_btc_per_kvbyte(&self) -> f64 {
// divide by 10^8 to get btc/vbyte, then multiply by 10^3 to get btc/kbyte
self.0.to_sat() as f64 / 100_000.0
}
}
/// A module used for serde serialization of bytes in hexadecimal format.
///
/// The module is compatible with the serde attribute.
Expand Down Expand Up @@ -1985,6 +2014,69 @@ pub struct FundRawTransactionResult {
pub change_position: i32,
}

#[derive(Clone, PartialEq, Eq, Debug, Default)]
pub struct BumpFeeOptions {
/// Confirmation target in blocks.
pub conf_target: Option<u16>,
/// Specify a fee rate instead of relying on the built-in fee estimator.
pub fee_rate: Option<FeeRate>,
/// Whether this transaction could be replaced due to BIP125 (replace-by-fee)
pub replaceable: Option<bool>,
/// The fee estimate mode
pub estimate_mode: Option<EstimateMode>,
}

impl BumpFeeOptions {
pub fn to_serializable(&self, version: usize) -> SerializableBumpFeeOptions {
let fee_rate = self.fee_rate.map(|x| {
if version < 210000 {
x.to_btc_per_kvbyte()
} else {
x.to_sat_per_vbyte()
}
});

SerializableBumpFeeOptions {
fee_rate,
conf_target: self.conf_target,
replaceable: self.replaceable,
estimate_mode: self.estimate_mode,
}
}
}

#[derive(Serialize, Clone, PartialEq, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct SerializableBumpFeeOptions {
#[serde(rename = "conf_target", skip_serializing_if = "Option::is_none")]
/// Confirmation target in blocks.
pub conf_target: Option<u16>,
/// Specify a fee rate instead of relying on the built-in fee estimator.
#[serde(rename = "fee_rate")]
pub fee_rate: Option<f64>,
/// Whether this transaction could be replaced due to BIP125 (replace-by-fee)
#[serde(skip_serializing_if = "Option::is_none")]
pub replaceable: Option<bool>,
/// The fee estimate mode
#[serde(rename = "estimate_mode", skip_serializing_if = "Option::is_none")]
pub estimate_mode: Option<EstimateMode>,
}

#[derive(Deserialize, Clone, PartialEq, Eq, Debug)]
#[serde(rename_all = "camelCase")]
pub struct BumpFeeResult {
/// The base64-encoded unsigned PSBT of the new transaction. Only returned when wallet private keys are disabled.
pub psbt: Option<String>,
/// The id of the new transaction. Only returned when wallet private keys are enabled.
pub txid: Option<bitcoin::Txid>,
#[serde(with = "bitcoin::amount::serde::as_btc")]
pub origfee: Amount,
#[serde(with = "bitcoin::amount::serde::as_btc")]
pub fee: Amount,
/// Errors encountered during processing.
pub errors: Vec<String>,
}

#[derive(Deserialize, Clone, PartialEq, Eq, Debug)]
pub struct GetBalancesResultEntry {
#[serde(with = "bitcoin::amount::serde::as_btc")]
Expand Down

0 comments on commit 333d265

Please sign in to comment.