Skip to content

Commit 8ee055d

Browse files
committed
Add fee_amount() and fee_rate() functions to PsbtUtils trait
1 parent 13cf72f commit 8ee055d

File tree

1 file changed

+59
-1
lines changed

1 file changed

+59
-1
lines changed

src/psbt/mod.rs

+59-1
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,20 @@
99
// You may not use this file except in accordance with one or both of these
1010
// licenses.
1111

12+
use crate::FeeRate;
1213
use bitcoin::util::psbt::PartiallySignedTransaction as Psbt;
1314
use bitcoin::TxOut;
1415

1516
pub trait PsbtUtils {
1617
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;
1726
}
1827

1928
impl PsbtUtils for Psbt {
@@ -37,15 +46,35 @@ impl PsbtUtils for Psbt {
3746
None
3847
}
3948
}
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+
}
4068
}
4169

4270
#[cfg(test)]
4371
mod test {
4472
use crate::bitcoin::TxIn;
4573
use crate::psbt::Psbt;
4674
use crate::wallet::AddressIndex;
75+
use crate::wallet::AddressIndex::New;
4776
use crate::wallet::{get_funded_wallet, test::get_test_wpkh};
48-
use crate::SignOptions;
77+
use crate::{psbt, FeeRate, SignOptions};
4978
use std::str::FromStr;
5079

5180
// from bip 174
@@ -118,4 +147,33 @@ mod test {
118147

119148
let _ = wallet.sign(&mut psbt, SignOptions::default()).unwrap();
120149
}
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+
}
121179
}

0 commit comments

Comments
 (0)