From 4f5d09288c350a81de427b5b594ecf3e10b46993 Mon Sep 17 00:00:00 2001 From: rustaceanrob Date: Sat, 5 Jul 2025 20:39:52 +0100 Subject: [PATCH] feat: add reading and writing PSBT files The Rust API makes it trivially simple to read and write PSBT to and from files. Bindings users may make use of this in air-gapped signing flows. The `PsbtError` already includes an `Io` variant, so we may make use of that error. --- bdk-ffi/src/bitcoin.rs | 20 ++++++++++++++++++++ bdk-ffi/src/error.rs | 16 ++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/bdk-ffi/src/bitcoin.rs b/bdk-ffi/src/bitcoin.rs index d7e5dd15..af47f686 100644 --- a/bdk-ffi/src/bitcoin.rs +++ b/bdk-ffi/src/bitcoin.rs @@ -32,6 +32,8 @@ use bdk_wallet::miniscript::psbt::PsbtExt; use bdk_wallet::serde_json; use std::fmt::Display; +use std::fs::File; +use std::io::{BufReader, BufWriter}; use std::ops::Deref; use std::str::FromStr; use std::sync::{Arc, Mutex}; @@ -495,6 +497,15 @@ impl Psbt { Ok(Arc::new(Psbt(Mutex::new(psbt)))) } + /// Create a new `Psbt` from a `.psbt` file. + #[uniffi::constructor] + pub(crate) fn from_file(path: String) -> Result { + let file = File::open(path)?; + let mut buf_read = BufReader::new(file); + let psbt: BdkPsbt = BdkPsbt::deserialize_from_reader(&mut buf_read)?; + Ok(Psbt(Mutex::new(psbt))) + } + /// Serialize the PSBT into a base64-encoded string. pub(crate) fn serialize(&self) -> String { let psbt = self.0.lock().unwrap().clone(); @@ -566,6 +577,15 @@ impl Psbt { } } + /// Write the `Psbt` to a file. Note that the file must not yet exist. + pub(crate) fn write_to_file(&self, path: String) -> Result<(), PsbtError> { + let file = File::create_new(path)?; + let mut writer = BufWriter::new(file); + let psbt = self.0.lock().unwrap(); + psbt.serialize_to_writer(&mut writer)?; + Ok(()) + } + /// Serializes the PSBT into a JSON string representation. pub(crate) fn json_serialize(&self) -> String { let psbt = self.0.lock().unwrap(); diff --git a/bdk-ffi/src/error.rs b/bdk-ffi/src/error.rs index 45a04c11..3e752f94 100644 --- a/bdk-ffi/src/error.rs +++ b/bdk-ffi/src/error.rs @@ -1438,6 +1438,22 @@ impl From for PsbtParseError { } } +impl From for PsbtError { + fn from(error: std::io::Error) -> Self { + PsbtError::Io { + error_message: error.to_string(), + } + } +} + +impl From for PsbtError { + fn from(error: bdk_wallet::bitcoin::io::Error) -> Self { + PsbtError::Io { + error_message: error.to_string(), + } + } +} + impl From for PsbtFinalizeError { fn from(value: BdkPsbtFinalizeError) -> Self { match value {