From 2459eb4fed15846ad1f10637e847b54f0d9959aa Mon Sep 17 00:00:00 2001 From: Matthew Date: Sat, 16 Dec 2023 19:24:02 -0600 Subject: [PATCH] feat: add calculate_fee and calculate_fee_rate on wallet --- .../org/bitcoindevkit/LiveWalletTest.kt | 8 ++++- bdk-ffi/src/bdk.udl | 18 +++++++++- bdk-ffi/src/bitcoin.rs | 9 +++++ bdk-ffi/src/error.rs | 35 +++++++++++++++++++ bdk-ffi/src/lib.rs | 3 ++ bdk-ffi/src/types.rs | 14 ++++++++ bdk-ffi/src/wallet.rs | 21 ++++++++--- .../org/bitcoindevkit/LiveWalletTest.kt | 8 ++++- bdk-python/tests/test_live_wallet.py | 5 +++ .../BitcoinDevKitTests/LiveWalletTests.swift | 5 +++ 10 files changed, 119 insertions(+), 7 deletions(-) create mode 100644 bdk-ffi/src/error.rs diff --git a/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/LiveWalletTest.kt b/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/LiveWalletTest.kt index b9a7d54a..1e71f61f 100644 --- a/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/LiveWalletTest.kt +++ b/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/LiveWalletTest.kt @@ -59,8 +59,14 @@ class LiveWalletTest { assertTrue(walletDidSign) val tx: Transaction = psbt.extractTx() - println("Txid is: ${tx.txid()}") + + val txFee = wallet.calculateFee(tx) + println("Tx fee is: ${tx.txid()}") + + val feeRate = wallet.calculateFeeRate(tx) + println("Tx fee is: ${tx.txid()} sat/vB") + esploraClient.broadcast(tx) } } diff --git a/bdk-ffi/src/bdk.udl b/bdk-ffi/src/bdk.udl index b90f059d..cfc56476 100644 --- a/bdk-ffi/src/bdk.udl +++ b/bdk-ffi/src/bdk.udl @@ -82,6 +82,16 @@ enum BdkError { "Psbt", }; +[Error] +interface CalculateFeeError { + MissingTxOut(sequence out_points); + NegativeFee(i64 fee); +}; + +interface FeeRate { + f32 as_sat_per_vb(); +}; + enum ChangeSpendPolicy { "ChangeAllowed", "OnlyChange", @@ -111,6 +121,12 @@ interface Wallet { SentAndReceivedValues sent_and_received([ByRef] Transaction tx); sequence transactions(); + + [Throws=CalculateFeeError] + u64 calculate_fee([ByRef] Transaction tx); + + [Throws=CalculateFeeError] + FeeRate calculate_fee_rate([ByRef] Transaction tx); }; interface Update {}; @@ -348,4 +364,4 @@ interface PartiallySignedTransaction { dictionary OutPoint { string txid; u32 vout; -}; +}; \ No newline at end of file diff --git a/bdk-ffi/src/bitcoin.rs b/bdk-ffi/src/bitcoin.rs index effa01a9..9061c3f0 100644 --- a/bdk-ffi/src/bitcoin.rs +++ b/bdk-ffi/src/bitcoin.rs @@ -300,6 +300,15 @@ impl From<&OutPoint> for BdkOutPoint { } } +impl From<&BdkOutPoint> for OutPoint { + fn from(outpoint: &BdkOutPoint) -> Self { + OutPoint { + txid: outpoint.txid.to_string(), + vout: outpoint.vout, + } + } +} + #[derive(Debug, Clone)] pub struct TxOut { pub value: u64, diff --git a/bdk-ffi/src/error.rs b/bdk-ffi/src/error.rs new file mode 100644 index 00000000..a3f7a7c5 --- /dev/null +++ b/bdk-ffi/src/error.rs @@ -0,0 +1,35 @@ +use crate::bitcoin::OutPoint; + +use bdk::chain::tx_graph::CalculateFeeError as BdkCalculateFeeError; + +use std::fmt; + +#[derive(Debug)] +pub enum CalculateFeeError { + MissingTxOut { out_points: Vec }, + NegativeFee { fee: i64 }, +} + +impl fmt::Display for CalculateFeeError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + CalculateFeeError::MissingTxOut { out_points } => { + write!(f, "Missing transaction output: {:?}", out_points) + } + CalculateFeeError::NegativeFee { fee } => write!(f, "Negative fee value: {}", fee), + } + } +} + +impl From for CalculateFeeError { + fn from(error: BdkCalculateFeeError) -> Self { + match error { + BdkCalculateFeeError::MissingTxOut(out_points) => CalculateFeeError::MissingTxOut { + out_points: out_points.iter().map(|op| op.into()).collect(), + }, + BdkCalculateFeeError::NegativeFee(fee) => CalculateFeeError::NegativeFee { fee }, + } + } +} + +impl std::error::Error for CalculateFeeError {} diff --git a/bdk-ffi/src/lib.rs b/bdk-ffi/src/lib.rs index b4ce7fda..ec86e0f4 100644 --- a/bdk-ffi/src/lib.rs +++ b/bdk-ffi/src/lib.rs @@ -1,5 +1,6 @@ mod bitcoin; mod descriptor; +mod error; mod esplora; mod keys; mod types; @@ -13,6 +14,7 @@ use crate::bitcoin::Script; use crate::bitcoin::Transaction; use crate::bitcoin::TxOut; use crate::descriptor::Descriptor; +use crate::error::CalculateFeeError; use crate::esplora::EsploraClient; use crate::keys::DerivationPath; use crate::keys::DescriptorPublicKey; @@ -21,6 +23,7 @@ use crate::keys::Mnemonic; use crate::types::AddressIndex; use crate::types::AddressInfo; use crate::types::Balance; +use crate::types::FeeRate; use crate::types::LocalUtxo; use crate::types::ScriptAmount; use crate::wallet::BumpFeeTxBuilder; diff --git a/bdk-ffi/src/types.rs b/bdk-ffi/src/types.rs index 1f03ea0f..df8086e1 100644 --- a/bdk-ffi/src/types.rs +++ b/bdk-ffi/src/types.rs @@ -7,8 +7,22 @@ use bdk::KeychainKind; use bdk::LocalUtxo as BdkLocalUtxo; +use bdk::FeeRate as BdkFeeRate; + use std::sync::Arc; +pub struct FeeRate(BdkFeeRate); + +impl FeeRate { + pub fn new(bdk_fee_rate: BdkFeeRate) -> Self { + FeeRate(bdk_fee_rate) + } + + pub fn as_sat_per_vb(&self) -> f32 { + self.0.as_sat_per_vb() + } +} + pub struct ScriptAmount { pub script: Arc