diff --git a/bdk-ffi/src/bdk.udl b/bdk-ffi/src/bdk.udl index 6a653e98..9f14aa3c 100644 --- a/bdk-ffi/src/bdk.udl +++ b/bdk-ffi/src/bdk.udl @@ -76,6 +76,7 @@ interface CreateTxError { MissingNonWitnessUtxo(string outpoint); MiniscriptPsbt(string error_message); PushBytesError(); + LockTimeConversionError(); }; [Error] @@ -714,6 +715,8 @@ interface TxBuilder { TxBuilder current_height(u32 height); + TxBuilder nlocktime(LockTime locktime); + [Throws=CreateTxError] Psbt finish([ByRef] Wallet wallet); }; @@ -725,6 +728,8 @@ interface BumpFeeTxBuilder { BumpFeeTxBuilder current_height(u32 height); + BumpFeeTxBuilder nlocktime(LockTime locktime); + [Throws=CreateTxError] Psbt finish([ByRef] Wallet wallet); }; diff --git a/bdk-ffi/src/error.rs b/bdk-ffi/src/error.rs index fbe9ba49..88805eb2 100644 --- a/bdk-ffi/src/error.rs +++ b/bdk-ffi/src/error.rs @@ -199,6 +199,9 @@ pub enum CreateTxError { #[error("attempt to prepare too many bytes to be pushed into script")] PushBytesError, + + #[error("invalid lock time value")] + LockTimeConversionError, } #[derive(Debug, thiserror::Error)] diff --git a/bdk-ffi/src/tx_builder.rs b/bdk-ffi/src/tx_builder.rs index 6d4d7e94..a19b133a 100644 --- a/bdk-ffi/src/tx_builder.rs +++ b/bdk-ffi/src/tx_builder.rs @@ -1,10 +1,11 @@ use crate::bitcoin::Psbt; use crate::error::CreateTxError; -use crate::types::ScriptAmount; +use crate::types::{LockTime, ScriptAmount}; use crate::wallet::Wallet; use bitcoin_ffi::{Amount, FeeRate, Script}; +use bdk_wallet::bitcoin::absolute::LockTime as BdkLockTime; use bdk_wallet::bitcoin::amount::Amount as BdkAmount; use bdk_wallet::bitcoin::script::PushBytesBuf; use bdk_wallet::bitcoin::Psbt as BdkPsbt; @@ -16,7 +17,7 @@ use bdk_wallet::KeychainKind; use std::collections::BTreeMap; use std::collections::HashMap; use std::collections::HashSet; -use std::convert::TryFrom; +use std::convert::{TryFrom, TryInto}; use std::str::FromStr; use std::sync::Arc; @@ -37,6 +38,7 @@ pub struct TxBuilder { pub(crate) sequence: Option, pub(crate) data: Vec, pub(crate) current_height: Option, + pub(crate) locktime: Option, } impl TxBuilder { @@ -57,6 +59,7 @@ impl TxBuilder { sequence: None, data: Vec::new(), current_height: None, + locktime: None, } } @@ -213,6 +216,13 @@ impl TxBuilder { }) } + pub(crate) fn nlocktime(&self, locktime: LockTime) -> Arc { + Arc::new(TxBuilder { + locktime: Some(locktime), + ..self.clone() + }) + } + pub(crate) fn finish(&self, wallet: &Arc) -> Result, CreateTxError> { // TODO: I had to change the wallet here to be mutable. Why is that now required with the 1.0 API? let mut wallet = wallet.get_wallet(); @@ -264,6 +274,11 @@ impl TxBuilder { if let Some(height) = self.current_height { tx_builder.current_height(height); } + // let bdk_locktime = locktime.try_into().map_err(CreateTxError::LockTimeConversionError)?; + if let Some(locktime) = &self.locktime { + let bdk_locktime: BdkLockTime = locktime.try_into()?; + tx_builder.nlocktime(bdk_locktime); + } let psbt = tx_builder.finish().map_err(CreateTxError::from)?; @@ -277,15 +292,17 @@ pub(crate) struct BumpFeeTxBuilder { pub(crate) fee_rate: Arc, pub(crate) sequence: Option, pub(crate) current_height: Option, + pub(crate) locktime: Option, } impl BumpFeeTxBuilder { pub(crate) fn new(txid: String, fee_rate: Arc) -> Self { - Self { + BumpFeeTxBuilder { txid, fee_rate, sequence: None, current_height: None, + locktime: None, } } @@ -303,6 +320,13 @@ impl BumpFeeTxBuilder { }) } + pub(crate) fn nlocktime(&self, locktime: LockTime) -> Arc { + Arc::new(BumpFeeTxBuilder { + locktime: Some(locktime), + ..self.clone() + }) + } + pub(crate) fn finish(&self, wallet: &Arc) -> Result, CreateTxError> { let txid = Txid::from_str(self.txid.as_str()).map_err(|_| CreateTxError::UnknownUtxo { outpoint: self.txid.clone(), @@ -316,6 +340,10 @@ impl BumpFeeTxBuilder { if let Some(height) = self.current_height { tx_builder.current_height(height); } + if let Some(locktime) = &self.locktime { + let bdk_locktime: BdkLockTime = locktime.try_into()?; + tx_builder.nlocktime(bdk_locktime); + } let psbt: BdkPsbt = tx_builder.finish()?; diff --git a/bdk-ffi/src/types.rs b/bdk-ffi/src/types.rs index 91bea8ed..12c27065 100644 --- a/bdk-ffi/src/types.rs +++ b/bdk-ffi/src/types.rs @@ -1,5 +1,5 @@ use crate::bitcoin::{Address, Transaction, TxOut}; -use crate::error::RequestBuilderError; +use crate::error::{CreateTxError, RequestBuilderError}; use bitcoin_ffi::Amount; use bitcoin_ffi::OutPoint; @@ -29,6 +29,7 @@ use bdk_wallet::LocalOutput as BdkLocalOutput; use bdk_wallet::Update as BdkUpdate; use std::collections::HashMap; +use std::convert::TryFrom; use std::sync::{Arc, Mutex}; #[derive(Debug)] @@ -405,6 +406,19 @@ impl From for LockTime { } } +impl TryFrom<&LockTime> for BdkLockTime { + type Error = CreateTxError; + + fn try_from(value: &LockTime) -> Result { + match value { + LockTime::Blocks { height } => BdkLockTime::from_height(*height) + .map_err(|_| CreateTxError::LockTimeConversionError), + LockTime::Seconds { consensus_time } => BdkLockTime::from_time(*consensus_time) + .map_err(|_| CreateTxError::LockTimeConversionError), + } + } +} + #[derive(Debug, Clone)] pub enum Satisfaction { Partial {