@@ -9,11 +9,12 @@ use bitcoin::{
9
9
} ;
10
10
use bitcoincore_rpc:: {
11
11
bitcoin:: { BlockHash , Transaction } ,
12
- json:: TestMempoolAcceptResult ,
12
+ json:: { EstimateMode , TestMempoolAcceptResult } ,
13
13
jsonrpc:: { error:: RpcError , Error as JsonRpcError } ,
14
14
Auth , Client , Error as BitcoinError , RpcApi ,
15
15
} ;
16
16
use num_derive:: FromPrimitive ;
17
+ use serde:: { Deserialize , Serialize } ;
17
18
use serde_json:: error:: Category as SerdeJsonCategory ;
18
19
use std:: { sync:: Arc , time:: Duration } ;
19
20
use tokio:: time:: { error:: Elapsed , sleep, timeout} ;
@@ -85,6 +86,101 @@ pub enum BitcoinRpcError {
85
86
RpcUnknownError = 0 ,
86
87
}
87
88
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
+
88
184
impl From < RpcError > for BitcoinRpcError {
89
185
fn from ( err : RpcError ) -> Self {
90
186
match num:: FromPrimitive :: from_i32 ( err. code ) {
@@ -323,6 +419,41 @@ impl BitcoinClient {
323
419
let transaction = signed_tx. transaction ( ) ?;
324
420
Ok ( transaction)
325
421
}
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
+ }
326
457
}
327
458
328
459
fn merklize ( left : Sha256dHash , right : Sha256dHash ) -> Sha256dHash {
0 commit comments