From 9f903932dc59e1cc955112492b699330b8806d93 Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Mon, 2 May 2022 19:23:47 -0700 Subject: [PATCH] Add BumpFeeTxBuilder --- CHANGELOG.md | 1 + src/bdk.udl | 9 +++++++ src/lib.rs | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 85 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 73fd99e..713c56e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] - Update BDK to version 0.18.0 +- Add BumpFeeTxBuilder to bump the fee on an unconfirmed tx created by the Wallet ## [v0.5.0] diff --git a/src/bdk.udl b/src/bdk.udl index 5429127..b722f09 100644 --- a/src/bdk.udl +++ b/src/bdk.udl @@ -158,6 +158,15 @@ interface TxBuilder { PartiallySignedBitcoinTransaction build([ByRef] Wallet wallet); }; +interface BumpFeeTxBuilder { + constructor(string txid, float new_fee_rate); + BumpFeeTxBuilder allow_shrinking(string address); + BumpFeeTxBuilder enable_rbf(); + BumpFeeTxBuilder enable_rbf_with_sequence(u32 nsequence); + [Throws=BdkError] + PartiallySignedBitcoinTransaction build([ByRef] Wallet wallet); +}; + dictionary ExtendedKeyInfo { string mnemonic; string xprv; diff --git a/src/lib.rs b/src/lib.rs index caa1396..22d99bd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ use bdk::bitcoin::hashes::hex::ToHex; use bdk::bitcoin::secp256k1::Secp256k1; use bdk::bitcoin::util::psbt::PartiallySignedTransaction; -use bdk::bitcoin::{Address, Network, Script}; +use bdk::bitcoin::{Address, Network, Script, Txid}; use bdk::blockchain::any::{AnyBlockchain, AnyBlockchainConfig}; use bdk::blockchain::{ electrum::ElectrumBlockchainConfig, esplora::EsploraBlockchainConfig, ConfigurableBlockchain, @@ -440,4 +440,78 @@ impl TxBuilder { } } +struct BumpFeeTxBuilder { + txid: String, + fee_rate: f32, + rbf: Option, + allow_shrinking: Option, +} + +impl BumpFeeTxBuilder { + fn new(txid: String, fee_rate: f32) -> Self { + Self { + txid, + fee_rate, + allow_shrinking: None, + rbf: None, + } + } + + fn allow_shrinking(&self, address: String) -> Arc { + Arc::new(Self { + txid: self.txid.clone(), + fee_rate: self.fee_rate, + allow_shrinking: Some(address), + rbf: self.rbf.clone(), + }) + } + + fn enable_rbf(&self) -> Arc { + Arc::new(Self { + txid: self.txid.clone(), + fee_rate: self.fee_rate, + rbf: Some(RbfValue::Default), + allow_shrinking: self.allow_shrinking.clone(), + }) + } + + fn enable_rbf_with_sequence(&self, nsequence: u32) -> Arc { + Arc::new(Self { + txid: self.txid.clone(), + fee_rate: self.fee_rate, + rbf: Some(RbfValue::Value(nsequence)), + allow_shrinking: self.allow_shrinking.clone(), + }) + } + + fn build(&self, wallet: &Wallet) -> Result, Error> { + let wallet = wallet.get_wallet(); + let txid = Txid::from_str(self.txid.as_str())?; + let mut tx_builder = wallet.build_fee_bump(txid)?; + tx_builder.fee_rate(FeeRate::from_sat_per_vb(self.fee_rate)); + if let Some(rbf) = &self.rbf { + match *rbf { + RbfValue::Default => { + tx_builder.enable_rbf(); + } + RbfValue::Value(nsequence) => { + tx_builder.enable_rbf_with_sequence(nsequence); + } + } + } + if let Some(allow_shrinking) = &self.allow_shrinking { + let address = + Address::from_str(allow_shrinking).map_err(|e| Error::Generic(e.to_string()))?; + let script = address.script_pubkey(); + tx_builder.allow_shrinking(script)?; + } + tx_builder + .finish() + .map(|(psbt, _)| PartiallySignedBitcoinTransaction { + internal: Mutex::new(psbt), + }) + .map(Arc::new) + } +} + uniffi::deps::static_assertions::assert_impl_all!(Wallet: Sync, Send);