Skip to content

Commit

Permalink
feat: add calculate_fee and calculate_fee_rate on wallet
Browse files Browse the repository at this point in the history
  • Loading branch information
reez committed Dec 27, 2023
1 parent cdec63e commit 8bb069a
Show file tree
Hide file tree
Showing 10 changed files with 120 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,14 @@ class LiveWalletTest {
assertTrue(walletDidSign)

val tx: Transaction = psbt.extractTx()

println("Txid is: ${tx.txid()}")

val txFee: ULong = wallet.calculateFee(tx)
println("Tx fee is: ${txFee}")

val feeRate: FeeRate = wallet.calculateFeeRate(tx)
println("Tx fee rate is: ${feeRate.asSatPerVb()} sat/vB")

esploraClient.broadcast(tx)
}
}
18 changes: 17 additions & 1 deletion bdk-ffi/src/bdk.udl
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,16 @@ enum BdkError {
"Psbt",
};

[Error]
interface CalculateFeeError {
MissingTxOut(sequence<OutPoint> out_points);
NegativeFee(i64 fee);
};

interface FeeRate {
f32 as_sat_per_vb();
};

enum ChangeSpendPolicy {
"ChangeAllowed",
"OnlyChange",
Expand Down Expand Up @@ -111,6 +121,12 @@ interface Wallet {
SentAndReceivedValues sent_and_received([ByRef] Transaction tx);

sequence<Transaction> transactions();

[Throws=CalculateFeeError]
u64 calculate_fee([ByRef] Transaction tx);

[Throws=CalculateFeeError]
FeeRate calculate_fee_rate([ByRef] Transaction tx);
};

interface Update {};
Expand Down Expand Up @@ -348,4 +364,4 @@ interface PartiallySignedTransaction {
dictionary OutPoint {
string txid;
u32 vout;
};
};
9 changes: 9 additions & 0 deletions bdk-ffi/src/bitcoin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
35 changes: 35 additions & 0 deletions bdk-ffi/src/error.rs
Original file line number Diff line number Diff line change
@@ -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<OutPoint> },
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<BdkCalculateFeeError> 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 {}
3 changes: 3 additions & 0 deletions bdk-ffi/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod bitcoin;
mod descriptor;
mod error;
mod esplora;
mod keys;
mod types;
Expand All @@ -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;
Expand All @@ -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;
Expand Down
14 changes: 14 additions & 0 deletions bdk-ffi/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Script>,
pub amount: u64,
Expand Down
22 changes: 18 additions & 4 deletions bdk-ffi/src/wallet.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::bitcoin::{OutPoint, PartiallySignedTransaction, Transaction};
use crate::descriptor::Descriptor;
use crate::types::Balance;
use crate::error::CalculateFeeError;
use crate::types::ScriptAmount;
use crate::types::{Balance, FeeRate};
use crate::Script;
use crate::{AddressIndex, AddressInfo, Network};

Expand All @@ -10,7 +11,7 @@ use bdk::bitcoin::psbt::PartiallySignedTransaction as BdkPartiallySignedTransact
use bdk::bitcoin::{OutPoint as BdkOutPoint, Sequence, Txid};
use bdk::wallet::tx_builder::ChangeSpendPolicy;
use bdk::wallet::Update as BdkUpdate;
use bdk::{Error as BdkError, FeeRate};
use bdk::{Error as BdkError, FeeRate as BdkFeeRate};
use bdk::{SignOptions, Wallet as BdkWallet};

use std::collections::HashSet;
Expand Down Expand Up @@ -98,6 +99,19 @@ impl Wallet {
.map(|tx| Arc::new(tx.tx_node.tx.clone().into()))
.collect()
}

pub fn calculate_fee(&self, tx: &Transaction) -> Result<u64, CalculateFeeError> {
self.get_wallet()
.calculate_fee(&tx.clone().into())
.map_err(|e| e.into())
}

pub fn calculate_fee_rate(&self, tx: &Transaction) -> Result<Arc<FeeRate>, CalculateFeeError> {
self.get_wallet()
.calculate_fee_rate(&tx.clone().into())
.map(|bdk_fee_rate| Arc::new(FeeRate::new(bdk_fee_rate)))
.map_err(|e| e.into())
}
}

pub struct SentAndReceivedValues {
Expand Down Expand Up @@ -473,7 +487,7 @@ impl TxBuilder {
tx_builder.manually_selected_only();
}
if let Some(sat_per_vb) = self.fee_rate {
tx_builder.fee_rate(FeeRate::from_sat_per_vb(sat_per_vb));
tx_builder.fee_rate(BdkFeeRate::from_sat_per_vb(sat_per_vb));
}
if let Some(fee_amount) = self.fee_absolute {
tx_builder.fee_absolute(fee_amount);
Expand Down Expand Up @@ -551,7 +565,7 @@ impl BumpFeeTxBuilder {
Txid::from_str(self.txid.as_str()).map_err(|e| BdkError::Generic(e.to_string()))?;
let mut wallet = wallet.get_wallet();
let mut tx_builder = wallet.build_fee_bump(txid)?;
tx_builder.fee_rate(FeeRate::from_sat_per_vb(self.fee_rate));
tx_builder.fee_rate(BdkFeeRate::from_sat_per_vb(self.fee_rate));
if let Some(allow_shrinking) = &self.allow_shrinking {
tx_builder.allow_shrinking(allow_shrinking.0.clone())?;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,14 @@ class LiveWalletTest {
assertTrue(walletDidSign)

val tx: Transaction = psbt.extractTx()

println("Txid is: ${tx.txid()}")

val txFee: ULong = wallet.calculateFee(tx)
println("Tx fee is: ${txFee}")

val feeRate: FeeRate = wallet.calculateFeeRate(tx)
println("Tx fee rate is: ${feeRate.asSatPerVb()} sat/vB")

esploraClient.broadcast(tx)
}
}
5 changes: 5 additions & 0 deletions bdk-python/tests/test_live_wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ def test_broadcast_transaction(self):
walletDidSign = wallet.sign(psbt)
self.assertTrue(walletDidSign)
tx = psbt.extract_tx()
print(f"Transaction Id: {tx.txid}")
fee = wallet.calculate_fee(tx)
print(f"Transaction Fee: {fee}")
fee_rate = wallet.calculate_fee_rate(tx)
print(f"Transaction Fee Rate: {fee_rate} sat/vB")

esploraClient.broadcast(tx)

Expand Down
5 changes: 5 additions & 0 deletions bdk-swift/Tests/BitcoinDevKitTests/LiveWalletTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ final class LiveWalletTests: XCTestCase {

let tx: Transaction = psbt.extractTx()
print(tx.txid())
let fee: UInt64 = try wallet.calculateFee(tx: tx)
print("Transaction Fee: \(fee)")
let feeRate: FeeRate = try wallet.calculateFeeRate(tx: tx)
print("Transaction Fee Rate: \(feeRate.asSatPerVb()) sat/vB")

try esploraClient.broadcast(transaction: tx)
}
}

0 comments on commit 8bb069a

Please sign in to comment.