Skip to content

Commit 4546aaf

Browse files
committed
feat: add calculate_fee and calculate_fee_rate on wallet
1 parent cdec63e commit 4546aaf

File tree

6 files changed

+93
-5
lines changed

6 files changed

+93
-5
lines changed

bdk-ffi/src/bdk.udl

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,17 @@ enum BdkError {
8282
"Psbt",
8383
};
8484

85+
[Error]
86+
interface CalculateFeeError {
87+
MissingTxOut(sequence<OutPoint> out_points);
88+
NegativeFee(i64 fee);
89+
};
90+
91+
interface FeeRate {
92+
[Name=from_sat_per_vb]
93+
constructor(float sat_per_vb);
94+
};
95+
8596
enum ChangeSpendPolicy {
8697
"ChangeAllowed",
8798
"OnlyChange",
@@ -111,6 +122,12 @@ interface Wallet {
111122
SentAndReceivedValues sent_and_received([ByRef] Transaction tx);
112123

113124
sequence<Transaction> transactions();
125+
126+
[Throws=CalculateFeeError]
127+
u64 calculate_fee([ByRef] Transaction tx);
128+
129+
[Throws=CalculateFeeError]
130+
FeeRate calculate_fee_rate([ByRef] Transaction tx);
114131
};
115132

116133
interface Update {};
@@ -348,4 +365,4 @@ interface PartiallySignedTransaction {
348365
dictionary OutPoint {
349366
string txid;
350367
u32 vout;
351-
};
368+
};

bdk-ffi/src/bitcoin.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,15 @@ impl From<&OutPoint> for BdkOutPoint {
300300
}
301301
}
302302

303+
impl From<&BdkOutPoint> for OutPoint {
304+
fn from(outpoint: &BdkOutPoint) -> Self {
305+
OutPoint {
306+
txid: outpoint.txid.to_string(),
307+
vout: outpoint.vout,
308+
}
309+
}
310+
}
311+
303312
#[derive(Debug, Clone)]
304313
pub struct TxOut {
305314
pub value: u64,

bdk-ffi/src/error.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
use crate::bitcoin::OutPoint;
2+
3+
use bdk::chain::tx_graph::CalculateFeeError as BdkCalculateFeeError;
4+
5+
use std::fmt;
6+
7+
#[derive(Debug)]
8+
pub enum CalculateFeeError {
9+
MissingTxOut { out_points: Vec<OutPoint> },
10+
NegativeFee { fee: i64 },
11+
}
12+
13+
impl fmt::Display for CalculateFeeError {
14+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
15+
match self {
16+
CalculateFeeError::MissingTxOut { out_points } => {
17+
write!(f, "Missing transaction output: {:?}", out_points)
18+
}
19+
CalculateFeeError::NegativeFee { fee } => write!(f, "Negative fee value: {}", fee),
20+
}
21+
}
22+
}
23+
24+
impl From<BdkCalculateFeeError> for CalculateFeeError {
25+
fn from(error: BdkCalculateFeeError) -> Self {
26+
match error {
27+
BdkCalculateFeeError::MissingTxOut(out_points) => CalculateFeeError::MissingTxOut {
28+
out_points: out_points.iter().map(|op| op.into()).collect(),
29+
},
30+
BdkCalculateFeeError::NegativeFee(fee) => CalculateFeeError::NegativeFee { fee },
31+
}
32+
}
33+
}
34+
35+
impl std::error::Error for CalculateFeeError {}

bdk-ffi/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
mod bitcoin;
22
mod descriptor;
3+
mod error;
34
mod esplora;
45
mod keys;
56
mod types;
@@ -13,6 +14,7 @@ use crate::bitcoin::Script;
1314
use crate::bitcoin::Transaction;
1415
use crate::bitcoin::TxOut;
1516
use crate::descriptor::Descriptor;
17+
use crate::error::CalculateFeeError;
1618
use crate::esplora::EsploraClient;
1719
use crate::keys::DerivationPath;
1820
use crate::keys::DescriptorPublicKey;
@@ -29,6 +31,8 @@ use crate::wallet::TxBuilder;
2931
use crate::wallet::Update;
3032
use crate::wallet::Wallet;
3133

34+
use crate::types::FeeRate;
35+
3236
use bdk::keys::bip39::WordCount;
3337
use bdk::wallet::tx_builder::ChangeSpendPolicy;
3438
use bdk::Error as BdkError;

bdk-ffi/src/types.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,18 @@ use bdk::KeychainKind;
77

88
use bdk::LocalUtxo as BdkLocalUtxo;
99

10+
use bdk::FeeRate as BdkFeeRate;
11+
1012
use std::sync::Arc;
1113

14+
pub struct FeeRate(BdkFeeRate);
15+
16+
impl FeeRate {
17+
pub fn from_sat_per_vb(sat_per_vb: f32) -> Self {
18+
FeeRate(BdkFeeRate::from_sat_per_vb(sat_per_vb))
19+
}
20+
}
21+
1222
pub struct ScriptAmount {
1323
pub script: Arc<Script>,
1424
pub amount: u64,

bdk-ffi/src/wallet.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use crate::bitcoin::{OutPoint, PartiallySignedTransaction, Transaction};
22
use crate::descriptor::Descriptor;
3-
use crate::types::Balance;
3+
use crate::error::CalculateFeeError;
44
use crate::types::ScriptAmount;
5+
use crate::types::{Balance, FeeRate};
56
use crate::Script;
67
use crate::{AddressIndex, AddressInfo, Network};
78

@@ -10,7 +11,7 @@ use bdk::bitcoin::psbt::PartiallySignedTransaction as BdkPartiallySignedTransact
1011
use bdk::bitcoin::{OutPoint as BdkOutPoint, Sequence, Txid};
1112
use bdk::wallet::tx_builder::ChangeSpendPolicy;
1213
use bdk::wallet::Update as BdkUpdate;
13-
use bdk::{Error as BdkError, FeeRate};
14+
use bdk::{Error as BdkError, FeeRate as BdkFeeRate};
1415
use bdk::{SignOptions, Wallet as BdkWallet};
1516

1617
use std::collections::HashSet;
@@ -98,6 +99,18 @@ impl Wallet {
9899
.map(|tx| Arc::new(tx.tx_node.tx.clone().into()))
99100
.collect()
100101
}
102+
103+
pub fn calculate_fee(&self, tx: &Transaction) -> Result<u64, CalculateFeeError> {
104+
let fee_result = self.get_wallet().calculate_fee(&tx.clone().into());
105+
fee_result.map_err(|err| err.into())
106+
}
107+
108+
pub fn calculate_fee_rate(&self, tx: &Transaction) -> Result<Arc<FeeRate>, CalculateFeeError> {
109+
let fee_rate_result = self.get_wallet().calculate_fee_rate(&tx.clone().into());
110+
fee_rate_result
111+
.map(|fee_rate| Arc::new(FeeRate::from_sat_per_vb(fee_rate.as_sat_per_vb())))
112+
.map_err(|err| err.into())
113+
}
101114
}
102115

103116
pub struct SentAndReceivedValues {
@@ -473,7 +486,7 @@ impl TxBuilder {
473486
tx_builder.manually_selected_only();
474487
}
475488
if let Some(sat_per_vb) = self.fee_rate {
476-
tx_builder.fee_rate(FeeRate::from_sat_per_vb(sat_per_vb));
489+
tx_builder.fee_rate(BdkFeeRate::from_sat_per_vb(sat_per_vb));
477490
}
478491
if let Some(fee_amount) = self.fee_absolute {
479492
tx_builder.fee_absolute(fee_amount);
@@ -551,7 +564,7 @@ impl BumpFeeTxBuilder {
551564
Txid::from_str(self.txid.as_str()).map_err(|e| BdkError::Generic(e.to_string()))?;
552565
let mut wallet = wallet.get_wallet();
553566
let mut tx_builder = wallet.build_fee_bump(txid)?;
554-
tx_builder.fee_rate(FeeRate::from_sat_per_vb(self.fee_rate));
567+
tx_builder.fee_rate(BdkFeeRate::from_sat_per_vb(self.fee_rate));
555568
if let Some(allow_shrinking) = &self.allow_shrinking {
556569
tx_builder.allow_shrinking(allow_shrinking.0.clone())?;
557570
}

0 commit comments

Comments
 (0)