Deprecated Wallet-Owned Signing APIs¶
Overview
- Lead Developer: @noahjoeris
- Pull Request: #536 (backport of #505)
- Feature Type: Non-Breaking/Deprecation
Overview¶
bdk_wallet 3.2.0 deprecates APIs for storing signing keys on Wallet and signing with them. They still compile; removal is planned for a later breaking release. See the 3.1 Wallet::sign_with_signers guide for the rationale and caller-owned signing flow.
New code should create wallets from public descriptors and keep keys outside the wallet. Private descriptors passed to Wallet::create still work and add keys for now.
Deprecated APIs¶
| Deprecated | Replacement |
|---|---|
Wallet::sign |
Psbt::sign (then finalize separately), or Wallet::sign_with_signers for SignOptions and finalization |
Wallet::{add_signer, set_keymap, set_keymaps, get_signers} |
Keep your own KeyMap or Xpriv. Wrap a KeyMap in KeyMapWrapper for Psbt::sign, or build a SignersContainer for sign_with_signers |
CreateParams::keymap, LoadParams::{keymap, extract_keys} |
Same; do not attach extra keys during create or load |
Wallet::policies |
public_descriptor(keychain).extract_policy(...) with caller-owned signers |
TxBuilder::policy_path |
Policy::get_condition, then TxBuilder::set_condition |
Descriptor secrets are not persisted, so loaded wallets do not recover them. Retain the keymap instead of calling LoadParams::extract_keys. FullyNodedExport::export_wallet now exports only public descriptors; retain private descriptors separately if you use them for recovery.
Spending Conditions¶
For single-path descriptors, TxBuilder derives lock requirements without set_condition. Use it when choosing among paths with different timelocks. It replaces the signer-dependent IDs used by deprecated policy_path with a Condition.
In the example below, we extract a policy, select a path, derive its Condition, and pass it to set_condition. Signer availability and PSBT status are not needed to derive the lock requirements.
use std::collections::BTreeMap;
use bdk_wallet::descriptor::policy::BuildSatisfaction;
use bdk_wallet::descriptor::ExtractPolicy;
use bdk_wallet::signer::SignersContainer;
use bdk_wallet::KeychainKind;
let policy = wallet
.public_descriptor(KeychainKind::External)
.extract_policy(
&SignersContainer::default(),
BuildSatisfaction::None,
wallet.secp_ctx(),
)?
.expect("descriptor has a spending policy");
let mut path = BTreeMap::new();
// Example: select branch 0 of a choice at the policy root.
path.insert(policy.id.clone(), vec![0]);
let condition = policy.get_condition(&path)?;
let mut builder = wallet.build_tx();
builder.set_condition(condition);
set_condition takes one Condition for the transaction. If both keychains may supply inputs with different lock requirements, combine their conditions with Condition::merge.
When the required lock is known, skip policy extraction and construct Condition directly. For an older(6) branch:
use bdk_wallet::bitcoin::Sequence;
use bdk_wallet::descriptor::Condition;
let mut builder = wallet.build_tx();
builder.set_condition(Condition {
csv: Some(Sequence(6)),
timelock: None,
});
set_condition takes precedence over policy_path. Without it, the deprecated path is resolved using wallet-owned signers, so only IDs from Wallet::policies match.