- Added support for Multipath (two-paths) descriptors.
- Fixed the data directory and config.toml permission being world-readable (0755/0644) to 0700/0600 on Unix.
+- Fixed `create_tx` and `bump_fee` panicking on malformed `--utxos` and `--add_data` values instead of returning an error
## [4.0.0]
#[derive(Debug, Error)]
pub enum BDKCliError {
+ #[error("Add UTXO error: {0}")]
+ AddUtxoError(#[from] bdk_wallet::tx_builder::AddUtxoError),
+
#[error("Cannot provide both a multipath descriptor and a separate internal descriptor.")]
AmbiguousDescriptors,
tx_builder.fee_rate(fee_rate);
}
if let Some(utxos) = &self.utxos {
- tx_builder
- .add_utxos(&utxos[..])
- .map_err(|_| bdk_wallet::error::CreateTxError::UnknownUtxo)?;
+ tx_builder.add_utxos(&utxos[..])?;
}
if let Some(unspendable) = &self.unspendable {
tx_builder.unspendable(unspendable.to_vec());
}
if let Some(base64_data) = &self.add_data {
- let op_return_data = BASE64_STANDARD
- .decode(base64_data)
- .map_err(|e| Error::Generic(e.to_string()))?;
+ let op_return_data = BASE64_STANDARD.decode(base64_data)?;
tx_builder.add_data(
&PushBytesBuf::try_from(op_return_data)
.map_err(|e| Error::Generic(e.to_string()))?,
}
if let Some(utxos) = &self.utxos {
- tx_builder.add_utxos(&utxos[..]).unwrap();
+ tx_builder.add_utxos(&utxos[..])?;
}
if let Some(unspendable) = &self.unspendable {
}
if let Some(base64_data) = &self.add_data {
- let op_return_data = BASE64_STANDARD.decode(base64_data).unwrap();
- tx_builder.add_data(&PushBytesBuf::try_from(op_return_data).unwrap());
+ let op_return_data = BASE64_STANDARD.decode(base64_data)?;
+ tx_builder.add_data(
+ &PushBytesBuf::try_from(op_return_data)
+ .map_err(|e| Error::Generic(e.to_string()))?,
+ );
} else if let Some(string_data) = &self.add_string {
- let data = PushBytesBuf::try_from(string_data.as_bytes().to_vec()).unwrap();
+ let data = PushBytesBuf::try_from(string_data.as_bytes().to_vec())
+ .map_err(|e| Error::Generic(e.to_string()))?;
tx_builder.add_data(&data);
}
let psbt = tx_builder.finish()?;
- // let psbt_base64 = BASE64_STANDARD.encode(psbt.serialize());
-
Ok(PsbtResult::new(&psbt, Some(false)))
}
}
}
if let Some(utxos) = &self.utxos {
- tx_builder
- .add_utxos(&utxos[..])
- .map_err(|_| bdk_wallet::error::CreateTxError::UnknownUtxo)?;
+ tx_builder.add_utxos(&utxos[..])?;
}
if let Some(unspendable) = &self.unspendable {
}
if let Some(base64_data) = &self.add_data {
- let op_return_data = BASE64_STANDARD
- .decode(base64_data)
- .map_err(|e| Error::Generic(e.to_string()))?;
+ let op_return_data = BASE64_STANDARD.decode(base64_data)?;
tx_builder.add_data(
&PushBytesBuf::try_from(op_return_data)
.map_err(|e| Error::Generic(e.to_string()))?,
}
if let Some(utxos) = &self.utxos {
- tx_builder.add_utxos(&utxos[..]).unwrap();
+ tx_builder.add_utxos(&utxos[..])?;
}
if let Some(unspendable) = &self.unspendable {
use tempfile::TempDir;
static WALLET_NAME: &str = "test_config_wallet";
+ /// A `--to` argument, the wallet is unfunded, so nothing is spent.
+ static RECIPIENT: &str = "tb1p4tp4l6glyr2gs94neqcpr5gha7344nfyznfkc8szkreflscsdkgqsdent4:10000";
/// Helper to spin up a sandboxed CLI with the generated descriptors
fn setup_wallet_config() -> (BdkCli, Command) {
.stderr(predicate::str::contains("Invalid"));
}
+ /// A malformed `create_tx` argument must be reported as an error (exit 1),
+ /// never as a panic (exit 101).
+ #[test]
+ fn test_create_tx_rejects_malformed_input_without_panicking() {
+ let (cli, mut cmd_init) = setup_wallet_config();
+ cmd_init.assert().success();
+
+ // Unknown outpoint
+ cli.wallet_cmd(&[
+ "--wallet",
+ WALLET_NAME,
+ "create_tx",
+ "--to",
+ RECIPIENT,
+ "--utxos",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:0",
+ ])
+ .assert()
+ .code(1)
+ .stderr(predicate::str::contains("UTXO not found"));
+
+ // Malformed base64
+ cli.wallet_cmd(&[
+ "--wallet",
+ WALLET_NAME,
+ "create_tx",
+ "--to",
+ RECIPIENT,
+ "--add_data",
+ "!!!not-base64!!!",
+ ])
+ .assert()
+ .code(1)
+ .stderr(predicate::str::contains("Base64 decoding error"));
+ }
+
#[cfg(feature = "message_signer")]
#[test]
fn test_sign_message_and_verify_message() {