@@ -9,11 +9,12 @@ use bitcoin::{
99} ;
1010use bitcoincore_rpc:: {
1111 bitcoin:: { BlockHash , Transaction } ,
12- json:: TestMempoolAcceptResult ,
12+ json:: { EstimateMode , TestMempoolAcceptResult } ,
1313 jsonrpc:: { error:: RpcError , Error as JsonRpcError } ,
1414 Auth , Client , Error as BitcoinError , RpcApi ,
1515} ;
1616use num_derive:: FromPrimitive ;
17+ use serde:: { Deserialize , Serialize } ;
1718use serde_json:: error:: Category as SerdeJsonCategory ;
1819use std:: { sync:: Arc , time:: Duration } ;
1920use tokio:: time:: { error:: Elapsed , sleep, timeout} ;
@@ -85,6 +86,101 @@ pub enum BitcoinRpcError {
8586 RpcUnknownError = 0 ,
8687}
8788
89+ /// A representation of a fee rate. Bitcoin Core uses different units in different
90+ /// versions. To avoid burdening the user with using the correct unit, this struct
91+ /// provides an umambiguous way to represent the fee rate, and the lib will perform
92+ /// the necessary conversions.
93+ #[ derive( Copy , Clone , PartialEq , Eq , Debug , Default ) ]
94+ pub struct FeeRate ( Amount ) ;
95+
96+ impl FeeRate {
97+ /// Construct FeeRate from the amount per vbyte
98+ pub fn per_vbyte ( amount_per_vbyte : Amount ) -> Self {
99+ // internal representation is amount per vbyte
100+ Self ( amount_per_vbyte)
101+ }
102+
103+ /// Construct FeeRate from the amount per kilo-vbyte
104+ pub fn per_kvbyte ( amount_per_kvbyte : Amount ) -> Self {
105+ // internal representation is amount per vbyte, so divide by 1000
106+ Self :: per_vbyte ( amount_per_kvbyte / 1000 )
107+ }
108+
109+ pub fn to_sat_per_vbyte ( & self ) -> f64 {
110+ // multiply by the number of decimals to get sat
111+ self . 0 . to_sat ( ) as f64 // TODO: Changed this
112+ }
113+
114+ pub fn to_btc_per_kvbyte ( & self ) -> f64 {
115+ // divide by 10^8 to get btc/vbyte, then multiply by 10^3 to get btc/kbyte
116+ self . 0 . to_sat ( ) as f64 / 100_000.0
117+ }
118+ }
119+
120+ #[ derive( Clone , PartialEq , Eq , Debug , Default ) ]
121+ pub struct BumpFeeOptions {
122+ /// Confirmation target in blocks.
123+ pub conf_target : Option < u16 > ,
124+ /// Specify a fee rate instead of relying on the built-in fee estimator.
125+ pub fee_rate : Option < FeeRate > ,
126+ /// Whether this transaction could be replaced due to BIP125 (replace-by-fee)
127+ pub replaceable : Option < bool > ,
128+ /// The fee estimate mode
129+ pub estimate_mode : Option < EstimateMode > ,
130+ }
131+
132+ #[ derive( Serialize , Clone , PartialEq , Debug , Default ) ]
133+ #[ serde( rename_all = "camelCase" ) ]
134+ pub struct SerializableBumpFeeOptions {
135+ #[ serde( rename = "conf_target" , skip_serializing_if = "Option::is_none" ) ]
136+ /// Confirmation target in blocks.
137+ pub conf_target : Option < u16 > ,
138+ /// Specify a fee rate instead of relying on the built-in fee estimator.
139+ #[ serde( rename = "fee_rate" ) ]
140+ pub fee_rate : Option < f64 > ,
141+ /// Whether this transaction could be replaced due to BIP125 (replace-by-fee)
142+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
143+ pub replaceable : Option < bool > ,
144+ /// The fee estimate mode
145+ #[ serde( rename = "estimate_mode" , skip_serializing_if = "Option::is_none" ) ]
146+ pub estimate_mode : Option < EstimateMode > ,
147+ }
148+
149+ impl BumpFeeOptions {
150+ pub fn to_serializable ( & self , version : usize ) -> SerializableBumpFeeOptions {
151+ let fee_rate = self . fee_rate . map ( |x| {
152+ if version < 210000 {
153+ x. to_btc_per_kvbyte ( )
154+ } else {
155+ x. to_sat_per_vbyte ( )
156+ }
157+ } ) ;
158+
159+ SerializableBumpFeeOptions {
160+ fee_rate,
161+ conf_target : self . conf_target ,
162+ replaceable : self . replaceable ,
163+ estimate_mode : self . estimate_mode ,
164+ }
165+ }
166+ }
167+
168+ #[ derive( Deserialize , Clone , Debug ) ]
169+ #[ serde( rename_all = "camelCase" ) ]
170+ pub struct BumpFeeResult {
171+ /// The base64-encoded unsigned PSBT of the new transaction. Only returned when wallet private
172+ /// keys are disabled.
173+ pub psbt : Option < String > ,
174+ /// The id of the new transaction. Only returned when wallet private keys are enabled.
175+ pub txid : Option < bitcoin:: Txid > ,
176+ /// The fee of the original transaction (before bumping), denominated in BTC.
177+ pub origfee : f64 ,
178+ /// The fee of the newly created bumped transaction, denominated in BTC.
179+ pub fee : f64 ,
180+ /// Errors encountered during processing.
181+ pub errors : Vec < String > ,
182+ }
183+
88184impl From < RpcError > for BitcoinRpcError {
89185 fn from ( err : RpcError ) -> Self {
90186 match num:: FromPrimitive :: from_i32 ( err. code ) {
@@ -323,6 +419,41 @@ impl BitcoinClient {
323419 let transaction = signed_tx. transaction ( ) ?;
324420 Ok ( transaction)
325421 }
422+
423+ pub fn bump_fee (
424+ & self ,
425+ txid : & Txid ,
426+ options : Option < & BumpFeeOptions > ,
427+ ) -> Result < BumpFeeResult , Error > {
428+ // Serialize options if provided
429+ let opts = match options {
430+ Some ( options) => Some ( options. to_serializable ( self . rpc . version ( ) ?) ) ,
431+ None => None ,
432+ } ;
433+
434+ // Prepare arguments
435+ let args = vec ! [ serde_json:: to_value( txid) ?, serde_json:: to_value( opts) ?] ;
436+
437+ // Call the "bumpfee" RPC method with borrowed args
438+ let result = self . rpc . call ( "bumpfee" , & args) ;
439+
440+ // Handle the result
441+ match result {
442+ Ok ( result_value) => {
443+ // Try to deserialize the result into the expected BumpFeeResult
444+ let result: Result < BumpFeeResult , _ > = serde_json:: from_value ( result_value) ;
445+
446+ match result {
447+ Ok ( bump_fee_result) => Ok ( bump_fee_result) ,
448+ Err ( err) => {
449+ println ! ( "Failed to deserialize into BumpFeeResult" ) ;
450+ Err ( err. into ( ) )
451+ }
452+ }
453+ }
454+ Err ( err) => Err ( err. into ( ) ) , // Handle the case where the RPC call fails
455+ }
456+ }
326457}
327458
328459fn merklize ( left : Sha256dHash , right : Sha256dHash ) -> Sha256dHash {
0 commit comments