9
9
// You may not use this file except in accordance with one or both of these
10
10
// licenses.
11
11
12
+ use crate :: FeeRate ;
12
13
use bitcoin:: util:: psbt:: PartiallySignedTransaction as Psbt ;
13
14
use bitcoin:: TxOut ;
14
15
15
16
pub trait PsbtUtils {
16
17
fn get_utxo_for ( & self , input_index : usize ) -> Option < TxOut > ;
18
+
19
+ /// The total transaction fee amount, sum of input amounts minus sum of output amounts, in Sats.
20
+ fn fee_amount ( & self ) -> u64 ;
21
+
22
+ /// The transaction's fee rate. This value will only be accurate if calculated AFTER the
23
+ /// `PartiallySignedTransaction` is finalized and all witness/signature data is added to the
24
+ /// transaction.
25
+ fn fee_rate ( & self ) -> FeeRate ;
17
26
}
18
27
19
28
impl PsbtUtils for Psbt {
@@ -37,15 +46,35 @@ impl PsbtUtils for Psbt {
37
46
None
38
47
}
39
48
}
49
+
50
+ fn fee_amount ( & self ) -> u64 {
51
+ let input_amount = & self
52
+ . inputs
53
+ . iter ( )
54
+ . fold ( 0 , |acc, i| acc + i. witness_utxo . as_ref ( ) . unwrap ( ) . value ) ;
55
+ let output_amount = & self
56
+ . unsigned_tx
57
+ . output
58
+ . iter ( )
59
+ . fold ( 0 , |acc, o| acc + o. value ) ;
60
+ input_amount - output_amount
61
+ }
62
+
63
+ fn fee_rate ( & self ) -> FeeRate {
64
+ let fee_amount = self . fee_amount ( ) ;
65
+ let weight = self . clone ( ) . extract_tx ( ) . weight ( ) ;
66
+ FeeRate :: from_wu ( fee_amount, weight)
67
+ }
40
68
}
41
69
42
70
#[ cfg( test) ]
43
71
mod test {
44
72
use crate :: bitcoin:: TxIn ;
45
73
use crate :: psbt:: Psbt ;
46
74
use crate :: wallet:: AddressIndex ;
75
+ use crate :: wallet:: AddressIndex :: New ;
47
76
use crate :: wallet:: { get_funded_wallet, test:: get_test_wpkh} ;
48
- use crate :: SignOptions ;
77
+ use crate :: { psbt , FeeRate , SignOptions } ;
49
78
use std:: str:: FromStr ;
50
79
51
80
// from bip 174
@@ -118,4 +147,33 @@ mod test {
118
147
119
148
let _ = wallet. sign ( & mut psbt, SignOptions :: default ( ) ) . unwrap ( ) ;
120
149
}
150
+
151
+ #[ test]
152
+ fn test_finalized_single_xprv_fee_rate ( ) {
153
+ use psbt:: PsbtUtils ;
154
+
155
+ let expected_fee_rate = 1.2345 ;
156
+
157
+ let ( wallet, _, _) = get_funded_wallet ( "wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)" ) ;
158
+ let addr = wallet. get_address ( New ) . unwrap ( ) ;
159
+ let mut builder = wallet. build_tx ( ) ;
160
+ builder. drain_to ( addr. script_pubkey ( ) ) . drain_wallet ( ) ;
161
+ builder. fee_rate ( FeeRate :: from_sat_per_vb ( expected_fee_rate) ) ;
162
+ let ( mut psbt, _) = builder. finish ( ) . unwrap ( ) ;
163
+
164
+ let fee_amount = psbt. fee_amount ( ) ;
165
+ dbg ! ( fee_amount) ;
166
+
167
+ let unfinalized_fee_rate = psbt. fee_rate ( ) ;
168
+ dbg ! ( unfinalized_fee_rate. as_sat_vb( ) ) ;
169
+
170
+ let finalized = wallet. sign ( & mut psbt, Default :: default ( ) ) . unwrap ( ) ;
171
+ assert ! ( finalized) ;
172
+
173
+ let finalized_fee_rate = psbt. fee_rate ( ) ;
174
+ dbg ! ( finalized_fee_rate. as_sat_vb( ) ) ;
175
+
176
+ assert ! ( finalized_fee_rate. as_sat_vb( ) >= expected_fee_rate) ;
177
+ assert ! ( finalized_fee_rate. as_sat_vb( ) < unfinalized_fee_rate. as_sat_vb( ) ) ;
178
+ }
121
179
}
0 commit comments