Skip to content

Implement create_psbt for Wallet#297

Open
ValuedMammal wants to merge 10 commits into
bitcoindevkit:masterfrom
ValuedMammal:feat/create_psbt
Open

Implement create_psbt for Wallet#297
ValuedMammal wants to merge 10 commits into
bitcoindevkit:masterfrom
ValuedMammal:feat/create_psbt

Conversation

@ValuedMammal

@ValuedMammal ValuedMammal commented Aug 12, 2025

Copy link
Copy Markdown
Collaborator

Description

This PR introduces a new PSBT construction flow and associated wallet APIs.

Primary additions:

  • New PsbtParams<Ctx> API with typed contexts (CreateTx and ReplaceTx) for transaction creation and replacement.
  • New wallet entry points for PSBT construction and RBF:
    • Wallet::create_psbt and Wallet::create_psbt_with_rng
    • Wallet::replace_by_fee, Wallet::replace_by_fee_with_rng, and Wallet::replace_by_fee_and_recipients
  • New error types for the new create-PSBT and RBF paths.
  • Supporting wallet helpers for transaction insertion and canonicalization-aware transaction listing.
  • New examples and expanded test coverage for expected PSBT/RBF behavior.
  • Generic TxOrdering<In, Out> updates used by the new selection/PSBT path

This work is part of the broader migration of transaction construction to bdk_tx, which uses miniscript's plan module under the hood. A key long-term goal is the move away from legacy policy-based transaction construction internals (#4).

fix #204

Notes to the reviewers

Suggested review order for this PR:

  1. Start with examples/psbt.rs and examples/replace_by_fee.rs for a high-level API walkthrough.
  2. Review src/psbt/params.rs in detail (types, state transitions, params semantics, and so on).
  3. Review the new wallet implementation in src/wallet/mod.rs (create-PSBT and RBF execution paths plus shared helpers).
  4. Review tests in tests/psbt.rs, tests/wallet.rs to ensure expected behavior and edge cases are covered.

Changelog notice

Changed

  • TxOrdering::Custom is generic over the input and output types.

Added

  • psbt::params module
  • PsbtParams struct
  • CoinSelectionStrategy enum
  • UtxoFilter struct

Added pub methods on Wallet

  • Wallet::create_psbt{_with_rng}
  • Wallet::replace_by_fee{_with_rng}
  • Wallet::replace_by_fee_and_recipients

Added examples

  • examples/psbt.rs
  • examples/replace_by_fee.rs

Checklists

@ValuedMammal ValuedMammal moved this to In Progress in BDK Wallet Aug 12, 2025
@ValuedMammal ValuedMammal added this to the Wallet 3.0.0 milestone Aug 12, 2025
@ValuedMammal ValuedMammal self-assigned this Aug 12, 2025
@coveralls

coveralls commented Aug 26, 2025

Copy link
Copy Markdown

Pull Request Test Coverage Report for Build 19016316365

Warning: This coverage report may be inaccurate.

This pull request's base commit is no longer the HEAD commit of its target branch. This means it includes changes from outside the original pull request, including, potentially, unrelated coverage changes.

Details

  • 524 of 656 (79.88%) changed or added relevant lines in 5 files are covered.
  • 299 unchanged lines in 8 files lost coverage.
  • Overall coverage decreased (-0.03%) to 84.779%

Changes Missing Coverage Covered Lines Changed/Added Lines %
src/wallet/tx_builder.rs 7 12 58.33%
src/wallet/error.rs 0 19 0.0%
src/wallet/mod.rs 317 357 88.8%
src/psbt/params.rs 183 251 72.91%
Files with Coverage Reduction New Missed Lines %
src/wallet/signer.rs 3 81.11%
src/wallet/params.rs 9 76.24%
src/descriptor/template.rs 10 97.46%
src/descriptor/mod.rs 13 88.04%
src/descriptor/dsl.rs 16 95.36%
src/keys/mod.rs 69 79.49%
src/descriptor/policy.rs 89 79.17%
src/wallet/mod.rs 90 84.1%
Totals Coverage Status
Change from base Build 18318022693: -0.03%
Covered Lines: 7536
Relevant Lines: 8889

💛 - Coveralls

@thunderbiscuit

Copy link
Copy Markdown
Member

I like the create_psbt name for the function. The Params struct I need to do a quick search but off the top of my head it feels like we have a few of those scattered across the crates named exactly that, so it gets confusing. In my exploration PR I used TransactionParams, but that's a bit long and verbose.

What do you envision the API for replace-by-fee transactions look like in this new bdk-tx world? I'm picturing something like Wallet::create_replacement_psbt which takes a WalletTx and another Params struct.

@ValuedMammal ValuedMammal moved this from In Progress to Needs Review in BDK Wallet Sep 11, 2025
@ValuedMammal ValuedMammal marked this pull request as ready for review September 11, 2025 15:39
@ValuedMammal ValuedMammal changed the title [WIP] Implement create_psbt for Wallet Implement create_psbt for Wallet Sep 11, 2025

@thunderbiscuit thunderbiscuit left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this is more of a conceptual review/question set, as I'm getting acquainted with the PR, and it also requires knowledge and understanding of the bdk-tx crate/workflow.

One general question I have is do you think is missing in functionality between this and the current TxBuilder? Can we make a todo list that compares functionality with the current TxBuilder to better visualize how close of a replacement this is, or if it only provides part of the functionality for now (and if so which parts)?

I haven't had time to look/test the examples and my day is over, but I'll come back to this on Monday.

Comment thread src/wallet/mod.rs
Comment thread src/psbt/params.rs Outdated
Comment thread src/psbt/params.rs
Comment thread src/psbt/params.rs Outdated
Comment thread src/psbt/params.rs Outdated
Comment thread src/wallet/mod.rs Outdated

@oleonardolima oleonardolima left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did an initial review, with simple comments/questions. Still need to take a deeper look into bdk-tx and do a more thorough review here.

Comment thread wallet/Cargo.toml Outdated
Comment thread src/wallet/error.rs
Comment on lines +264 to +267
/// No Bnb solution.
Bnb(bdk_coin_select::NoBnbSolution),
/// Non-sufficient funds
InsufficientFunds(bdk_coin_select::InsufficientFunds),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we have a generic CS error instead ?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate on what you mean by generic CS error?

Comment thread src/wallet/mod.rs Outdated
@ValuedMammal

Copy link
Copy Markdown
Collaborator Author

Thank you for the quick review @thunderbiscuit @oleonardolima.

@ValuedMammal

ValuedMammal commented Sep 20, 2025

Copy link
Copy Markdown
Collaborator Author

TxBuilder vs PsbtParams feature comparison

subject to change

Feature TxBuilder PsbtParams Status
internal_policy_path NA
external_policy_path NA
manually_selected_only Done
include_output_redeem_witness_script NA
current_height Done
fee_rate Done
fee_absolute _
sighash (type) Done
ordering Done
add_global_xpubs Done
allow_dust _
unspendable NA
recipients Done
utxos Done
drain_wallet Done
drain_to/change_script Done
locktime Done
version Done
fallback_sequence Done
bumping_fee Done
only_witness_utxo Done
change_policy Done
add_foreign_utxo / planned_input Done
filter_utxos Done

N/A:
- *_policy_path: deprecated, use add_assets instead
- include_output_redeem_witness_script: deprecated, no longer used
- unspendable: NA, refer to filter_utxos
- change_policy: NA, refer to filter_utxos

@ValuedMammal

ValuedMammal commented Oct 1, 2025

Copy link
Copy Markdown
Collaborator Author
  • We need a way to implement fee_absolute or find out if this is possible using bdk_coin_select.
  • Note that UtxoFilter can accomplish a number of things from the old interface, such as "change policy" and "unspendable".
  • To prevent multiple parameters from trying to dictate the current height, the current_height option can be achieved via the assets.absolute_timelock.
  • current_height renamed to maturity_height, as it's only used as a parameter to is_mature.

@ValuedMammal

Copy link
Copy Markdown
Collaborator Author

We need a way to implement fee_absolute or find out if this is possible using bdk_coin_select.

I think a straightforward approach is to set a target feerate of 0 and add the fee amount to the output value_sum. The effect is to raise the cost of meeting the target by the amount of the target fee.

I can see it being relevant to CPFP, since there we're less concerned about the feerate of an individual tx and more so with the fee needed to bump a package to a target feerate.

evanlinjin added a commit to evanlinjin/bdk-tx that referenced this pull request Jun 27, 2026
Bridge between bdk_wallet and bdk_tx, exposed as a `WalletTxExt` extension
trait on `bdk_wallet::Wallet`. Keeping it in its own crate means neither base
crate depends on the other: `bdk_wallet` stays stable, `bdk_tx` stays free to
move, and the bridge absorbs the coupling (the decoupling argument from
bitcoindevkit/bdk_wallet#297).

Three-stage pipeline:
- `candidates`/`candidates_with`/`rbf_candidates` -> `CandidateSet` (stage 1).
- `select`/`select_with_rng` -> `(TxTemplate, Option<AddressInfo>)` (stage 2):
  a pure read that peeks the auto-derived change address; commit it with
  `commit_change` (reveal + mark used) when you use the tx, or ignore it on
  abandon. Emit the PSBT directly via `bdk_tx::TxTemplate::build_psbt`.
- `add_global_xpubs` fills the PSBT's global xpubs (the only emission step that
  needs the wallet).

Ported from the bdk_wallet#502 PoC, re-expressed over the integrated bdk_tx API
and the wallet's public accessors. MTP is faked from the confirmation block
time; UTXO locking is honored; `longterm_feerate` lives on `SelectParams` and
feeds the waste-aware change policy for every strategy. End-to-end tests cover
the pipeline, RBF-free candidate filtering, change commit, and error paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
evanlinjin added a commit to evanlinjin/bdk-tx that referenced this pull request Jun 27, 2026
Bridge between bdk_wallet and bdk_tx, exposed as a `WalletTxExt` extension
trait on `bdk_wallet::Wallet`. Keeping it in its own crate means neither base
crate depends on the other: `bdk_wallet` stays stable, `bdk_tx` stays free to
move, and the bridge absorbs the coupling (the decoupling argument from
bitcoindevkit/bdk_wallet#297).

Three-stage pipeline:
- `candidates`/`candidates_with`/`rbf_candidates` -> `CandidateSet` (stage 1).
- `select`/`select_with_rng` -> `(TxTemplate, Option<AddressInfo>)` (stage 2):
  a pure read that peeks the auto-derived change address; commit it with
  `commit_change` (reveal + mark used) when you use the tx, or ignore it on
  abandon. Emit the PSBT directly via `bdk_tx::TxTemplate::build_psbt`.
- `add_global_xpubs` fills the PSBT's global xpubs (the only emission step that
  needs the wallet).

Ported from the bdk_wallet#502 PoC, re-expressed over the integrated bdk_tx API
and the wallet's public accessors. MTP is faked from the confirmation block
time; UTXO locking is honored; `longterm_feerate` lives on `SelectParams` and
feeds the waste-aware change policy for every strategy. End-to-end tests cover
the pipeline, RBF-free candidate filtering, change commit, and error paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
evanlinjin added a commit to evanlinjin/bdk-tx that referenced this pull request Jun 27, 2026
Bridge between bdk_wallet and bdk_tx, exposed as a `WalletTxExt` extension
trait on `bdk_wallet::Wallet`. Keeping it in its own crate means neither base
crate depends on the other: `bdk_wallet` stays stable, `bdk_tx` stays free to
move, and the bridge absorbs the coupling (the decoupling argument from
bitcoindevkit/bdk_wallet#297).

Three-stage pipeline:
- `candidates`/`candidates_with`/`rbf_candidates` -> `CandidateSet` (stage 1).
- `select` -> `(TxTemplate, Option<AddressInfo>)` (stage 2): a pure read over a
  borrowed `&CandidateSet` (re-runnable) that peeks the auto-derived change
  address; commit it with `commit_change` (reveal + mark used) when you use the
  tx, or ignore it on abandon. The caller supplies the RNG. Emit the PSBT
  directly via `bdk_tx::TxTemplate::build_psbt`.
- `add_global_xpubs` fills the PSBT's global xpubs (the only emission step that
  needs the wallet).

Ported from the bdk_wallet#502 PoC, re-expressed over the integrated bdk_tx API
and the wallet's public accessors. MTP is faked from the confirmation block
time; UTXO locking is honored; `longterm_feerate` lives on `SelectParams` and
feeds the waste-aware change policy for every strategy. End-to-end tests cover
the pipeline, candidate filtering, change commit, and error paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
evanlinjin added a commit to evanlinjin/bdk-tx that referenced this pull request Jun 27, 2026
Bridge between bdk_wallet and bdk_tx, exposed as a `WalletTxExt` extension
trait on `bdk_wallet::Wallet`. Keeping it in its own crate means neither base
crate depends on the other: `bdk_wallet` stays stable, `bdk_tx` stays free to
move, and the bridge absorbs the coupling (the decoupling argument from
bitcoindevkit/bdk_wallet#297).

Three-stage pipeline:
- `candidates`/`candidates_with`/`rbf_candidates` -> `CandidateSet` (stage 1).
- `select` -> `(TxTemplate, Option<AddressInfo>)` (stage 2): a pure read over a
  borrowed `&CandidateSet` (re-runnable) that peeks the auto-derived change
  address; commit it with `commit_change` (reveal + mark used) when you use the
  tx, or ignore it on abandon. The caller supplies the RNG. Emit the PSBT
  directly via `bdk_tx::TxTemplate::build_psbt`.
- `add_global_xpubs` fills the PSBT's global xpubs (the only emission step that
  needs the wallet).

Ported from the bdk_wallet#502 PoC, re-expressed over the integrated bdk_tx API
and the wallet's public accessors. MTP is faked from the confirmation block
time; UTXO locking is honored; `longterm_feerate` lives on `SelectParams` and
feeds the waste-aware change policy for every strategy. End-to-end tests cover
the pipeline, candidate filtering, change commit, and error paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
evanlinjin added a commit to evanlinjin/bdk-tx that referenced this pull request Jun 27, 2026
Bridge between bdk_wallet and bdk_tx, exposed as a `WalletTxExt` extension
trait on `bdk_wallet::Wallet`. Keeping it in its own crate means neither base
crate depends on the other: `bdk_wallet` stays stable, `bdk_tx` stays free to
move, and the bridge absorbs the coupling (the decoupling argument from
bitcoindevkit/bdk_wallet#297).

Three-stage pipeline:
- `candidates`/`candidates_with`/`rbf_candidates` -> `CandidateSet` (stage 1).
- `select` -> `(TxTemplate, Option<AddressInfo>)` (stage 2): a pure read over a
  borrowed `&CandidateSet` (re-runnable) that peeks the auto-derived change
  address; commit it with `commit_change` (reveal + mark used) when you use the
  tx, or ignore it on abandon. The caller supplies the RNG. Emit the PSBT
  directly via `bdk_tx::TxTemplate::build_psbt`.
- `add_global_xpubs` fills the PSBT's global xpubs (the only emission step that
  needs the wallet).

Ported from the bdk_wallet#502 PoC, re-expressed over the integrated bdk_tx API
and the wallet's public accessors. MTP is faked from the confirmation block
time; UTXO locking is honored; `longterm_feerate` lives on `SelectParams` and
feeds the waste-aware change policy for every strategy. End-to-end tests cover
the pipeline, candidate filtering, change commit, and error paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
evanlinjin added a commit to evanlinjin/bdk-tx that referenced this pull request Jun 27, 2026
Bridge between bdk_wallet and bdk_tx, exposed as a `WalletTxExt` extension
trait on `bdk_wallet::Wallet`. Keeping it in its own crate means neither base
crate depends on the other: `bdk_wallet` stays stable, `bdk_tx` stays free to
move, and the bridge absorbs the coupling (the decoupling argument from
bitcoindevkit/bdk_wallet#297).

Three-stage pipeline:
- `candidates`/`candidates_with`/`rbf_candidates` -> `CandidateSet` (stage 1).
- `select` -> `(TxTemplate, Option<AddressInfo>)` (stage 2): a pure read over a
  borrowed `&CandidateSet` (re-runnable) that peeks the auto-derived change
  address; commit it with `commit_change` (reveal + mark used) when you use the
  tx, or ignore it on abandon. The caller supplies the RNG. Emit the PSBT
  directly via `bdk_tx::TxTemplate::build_psbt`.
- `add_global_xpubs` fills the PSBT's global xpubs (the only emission step that
  needs the wallet).

Ported from the bdk_wallet#502 PoC, re-expressed over the integrated bdk_tx API
and the wallet's public accessors. MTP is faked from the confirmation block
time; UTXO locking is honored; `longterm_feerate` lives on `SelectParams` and
feeds the waste-aware change policy for every strategy. End-to-end tests cover
the pipeline, candidate filtering, change commit, and error paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
evanlinjin added a commit to evanlinjin/bdk-tx that referenced this pull request Jun 27, 2026
Bridge between bdk_wallet and bdk_tx, exposed as a `WalletTxExt` extension
trait on `bdk_wallet::Wallet`. Keeping it in its own crate means neither base
crate depends on the other: `bdk_wallet` stays stable, `bdk_tx` stays free to
move, and the bridge absorbs the coupling (the decoupling argument from
bitcoindevkit/bdk_wallet#297).

Three-stage pipeline:
- `candidates`/`candidates_with`/`rbf_candidates` -> `CandidateSet` (stage 1).
- `select` -> `(TxTemplate, Option<AddressInfo>)` (stage 2): a pure read over a
  borrowed `&CandidateSet` (re-runnable) that peeks the auto-derived change
  address; commit it with `commit_change` (reveal + mark used) when you use the
  tx, or ignore it on abandon. The caller supplies the RNG. Emit the PSBT
  directly via `bdk_tx::TxTemplate::build_psbt`.
- `add_global_xpubs` fills the PSBT's global xpubs (the only emission step that
  needs the wallet).

Ported from the bdk_wallet#502 PoC, re-expressed over the integrated bdk_tx API
and the wallet's public accessors. MTP is faked from the confirmation block
time; UTXO locking is honored; `longterm_feerate` lives on `SelectParams` and
feeds the waste-aware change policy for every strategy. End-to-end tests cover
the pipeline, candidate filtering, change commit, and error paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
evanlinjin added a commit to evanlinjin/bdk-tx that referenced this pull request Jun 27, 2026
Bridge between bdk_wallet and bdk_tx, exposed as a `WalletTxExt` extension
trait on `bdk_wallet::Wallet`. Keeping it in its own crate means neither base
crate depends on the other: `bdk_wallet` stays stable, `bdk_tx` stays free to
move, and the bridge absorbs the coupling (the decoupling argument from
bitcoindevkit/bdk_wallet#297).

Three-stage pipeline:
- `candidates`/`candidates_with`/`rbf_candidates` -> `CandidateSet` (stage 1).
- `select` -> `(TxTemplate, Option<AddressInfo>)` (stage 2): a pure read over a
  borrowed `&CandidateSet` (re-runnable) that peeks the auto-derived change
  address; commit it with `commit_change` (reveal + mark used) when you use the
  tx, or ignore it on abandon. The caller supplies the RNG. Emit the PSBT
  directly via `bdk_tx::TxTemplate::build_psbt`.
- `add_global_xpubs` fills the PSBT's global xpubs (the only emission step that
  needs the wallet).

Ported from the bdk_wallet#502 PoC, re-expressed over the integrated bdk_tx API
and the wallet's public accessors. MTP is faked from the confirmation block
time; UTXO locking is honored; `longterm_feerate` lives on `SelectParams` and
feeds the waste-aware change policy for every strategy. End-to-end tests cover
the pipeline, candidate filtering, change commit, and error paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
evanlinjin added a commit to evanlinjin/bdk-tx that referenced this pull request Jun 27, 2026
Bridge between bdk_wallet and bdk_tx, exposed as a `WalletTxExt` extension
trait on `bdk_wallet::Wallet`. Keeping it in its own crate means neither base
crate depends on the other: `bdk_wallet` stays stable, `bdk_tx` stays free to
move, and the bridge absorbs the coupling (the decoupling argument from
bitcoindevkit/bdk_wallet#297).

Three-stage pipeline:
- `candidates`/`candidates_with`/`rbf_candidates` -> `CandidateSet` (stage 1).
- `select` -> `(TxTemplate, Option<AddressInfo>)` (stage 2): a pure read over a
  borrowed `&CandidateSet` (re-runnable) that peeks the auto-derived change
  address; commit it with `commit_change` (reveal + mark used) when you use the
  tx, or ignore it on abandon. The caller supplies the RNG. Emit the PSBT
  directly via `bdk_tx::TxTemplate::build_psbt`.
- `add_global_xpubs` fills the PSBT's global xpubs (the only emission step that
  needs the wallet).

Ported from the bdk_wallet#502 PoC, re-expressed over the integrated bdk_tx API
and the wallet's public accessors. MTP is faked from the confirmation block
time; UTXO locking is honored; `longterm_feerate` lives on `SelectParams` and
feeds the waste-aware change policy for every strategy. End-to-end tests cover
the pipeline, candidate filtering, change commit, and error paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
evanlinjin added a commit to evanlinjin/bdk-tx that referenced this pull request Jun 27, 2026
Bridge between bdk_wallet and bdk_tx, exposed as a `WalletTxExt` extension
trait on `bdk_wallet::Wallet`. Keeping it in its own crate means neither base
crate depends on the other: `bdk_wallet` stays stable, `bdk_tx` stays free to
move, and the bridge absorbs the coupling (the decoupling argument from
bitcoindevkit/bdk_wallet#297).

Three-stage pipeline:
- `candidates`/`candidates_with`/`rbf_candidates` -> `CandidateSet` (stage 1).
- `select` -> `(TxTemplate, Option<AddressInfo>)` (stage 2): a pure read over a
  borrowed `&CandidateSet` (re-runnable) that peeks the auto-derived change
  address; commit it with `commit_change` (reveal + mark used) when you use the
  tx, or ignore it on abandon. The caller supplies the RNG. Emit the PSBT
  directly via `bdk_tx::TxTemplate::build_psbt`.
- `add_global_xpubs` fills the PSBT's global xpubs (the only emission step that
  needs the wallet).

Ported from the bdk_wallet#502 PoC, re-expressed over the integrated bdk_tx API
and the wallet's public accessors. MTP is faked from the confirmation block
time; UTXO locking is honored; `longterm_feerate` lives on `SelectParams` and
feeds the waste-aware change policy for every strategy. End-to-end tests cover
the pipeline, candidate filtering, change commit, and error paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
evanlinjin added a commit to evanlinjin/bdk-tx that referenced this pull request Jun 27, 2026
Bridge between bdk_wallet and bdk_tx, exposed as a `WalletTxExt` extension
trait on `bdk_wallet::Wallet`. Keeping it in its own crate means neither base
crate depends on the other: `bdk_wallet` stays stable, `bdk_tx` stays free to
move, and the bridge absorbs the coupling (the decoupling argument from
bitcoindevkit/bdk_wallet#297).

Three-stage pipeline:
- `candidates`/`candidates_with`/`rbf_candidates` -> `CandidateSet` (stage 1).
- `select` -> `(TxTemplate, Option<AddressInfo>)` (stage 2): a pure read over a
  borrowed `&CandidateSet` (re-runnable) that peeks the auto-derived change
  address; commit it with `commit_change` (reveal + mark used) when you use the
  tx, or ignore it on abandon. The caller supplies the RNG. Emit the PSBT
  directly via `bdk_tx::TxTemplate::build_psbt`.
- `add_global_xpubs` fills the PSBT's global xpubs (the only emission step that
  needs the wallet).

Ported from the bdk_wallet#502 PoC, re-expressed over the integrated bdk_tx API
and the wallet's public accessors. MTP is faked from the confirmation block
time; UTXO locking is honored; `longterm_feerate` lives on `SelectParams` and
feeds the waste-aware change policy for every strategy. End-to-end tests cover
the pipeline, candidate filtering, change commit, and error paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
evanlinjin added a commit to evanlinjin/bdk-tx that referenced this pull request Jun 27, 2026
Bridge between bdk_wallet and bdk_tx, exposed as a `WalletTxExt` extension
trait on `bdk_wallet::Wallet`. Keeping it in its own crate means neither base
crate depends on the other: `bdk_wallet` stays stable, `bdk_tx` stays free to
move, and the bridge absorbs the coupling (the decoupling argument from
bitcoindevkit/bdk_wallet#297).

Three-stage pipeline:
- `candidates`/`candidates_with`/`rbf_candidates` -> `CandidateSet` (stage 1).
- `select` -> `(TxTemplate, Option<AddressInfo>)` (stage 2): a pure read over a
  borrowed `&CandidateSet` (re-runnable) that peeks the auto-derived change
  address; commit it with `commit_change` (reveal + mark used) when you use the
  tx, or ignore it on abandon. The caller supplies the RNG. Emit the PSBT
  directly via `bdk_tx::TxTemplate::build_psbt`.
- `add_global_xpubs` fills the PSBT's global xpubs (the only emission step that
  needs the wallet).

Ported from the bdk_wallet#502 PoC, re-expressed over the integrated bdk_tx API
and the wallet's public accessors. MTP is faked from the confirmation block
time; UTXO locking is honored; `longterm_feerate` lives on `SelectParams` and
feeds the waste-aware change policy for every strategy. End-to-end tests cover
the pipeline, candidate filtering, change commit, and error paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
evanlinjin added a commit to evanlinjin/bdk-tx that referenced this pull request Jun 27, 2026
Bridge between bdk_wallet and bdk_tx, exposed as a `WalletTxExt` extension
trait on `bdk_wallet::Wallet`. Keeping it in its own crate means neither base
crate depends on the other: `bdk_wallet` stays stable, `bdk_tx` stays free to
move, and the bridge absorbs the coupling (the decoupling argument from
bitcoindevkit/bdk_wallet#297).

Three-stage pipeline:
- `candidates`/`candidates_with`/`rbf_candidates` -> `CandidateSet` (stage 1).
- `select` -> `(TxTemplate, Option<AddressInfo>)` (stage 2): a pure read over a
  borrowed `&CandidateSet` (re-runnable) that peeks the auto-derived change
  address; commit it with `commit_change` (reveal + mark used) when you use the
  tx, or ignore it on abandon. The caller supplies the RNG. Emit the PSBT
  directly via `bdk_tx::TxTemplate::build_psbt`.
- `add_global_xpubs` fills the PSBT's global xpubs (the only emission step that
  needs the wallet).

Ported from the bdk_wallet#502 PoC, re-expressed over the integrated bdk_tx API
and the wallet's public accessors. MTP is faked from the confirmation block
time; UTXO locking is honored; `longterm_feerate` lives on `SelectParams` and
feeds the waste-aware change policy for every strategy. End-to-end tests cover
the pipeline, candidate filtering, change commit, and error paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
evanlinjin added a commit to evanlinjin/bdk-tx that referenced this pull request Jun 27, 2026
Bridge between bdk_wallet and bdk_tx, exposed as a `WalletTxExt` extension
trait on `bdk_wallet::Wallet`. Keeping it in its own crate means neither base
crate depends on the other: `bdk_wallet` stays stable, `bdk_tx` stays free to
move, and the bridge absorbs the coupling (the decoupling argument from
bitcoindevkit/bdk_wallet#297).

Three-stage pipeline:
- `candidates`/`candidates_with`/`rbf_candidates` -> `CandidateSet` (stage 1).
- `select` -> `(TxTemplate, Option<AddressInfo>)` (stage 2): a pure read over a
  borrowed `&CandidateSet` (re-runnable) that peeks the auto-derived change
  address; commit it with `commit_change` (reveal + mark used) when you use the
  tx, or ignore it on abandon. The caller supplies the RNG. Emit the PSBT
  directly via `bdk_tx::TxTemplate::build_psbt`.
- `add_global_xpubs` fills the PSBT's global xpubs (the only emission step that
  needs the wallet).

Ported from the bdk_wallet#502 PoC, re-expressed over the integrated bdk_tx API
and the wallet's public accessors. MTP is faked from the confirmation block
time; UTXO locking is honored; `longterm_feerate` lives on `SelectParams` and
feeds the waste-aware change policy for every strategy. End-to-end tests cover
the pipeline, candidate filtering, change commit, and error paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
evanlinjin added a commit to evanlinjin/bdk-tx that referenced this pull request Jun 27, 2026
Bridge between bdk_wallet and bdk_tx, exposed as a `WalletTxExt` extension
trait on `bdk_wallet::Wallet`. Keeping it in its own crate means neither base
crate depends on the other: `bdk_wallet` stays stable, `bdk_tx` stays free to
move, and the bridge absorbs the coupling (the decoupling argument from
bitcoindevkit/bdk_wallet#297).

Three-stage pipeline:
- `candidates`/`candidates_with`/`rbf_candidates` -> `CandidateSet` (stage 1).
- `select` -> `(TxTemplate, Option<AddressInfo>)` (stage 2): a pure read over a
  borrowed `&CandidateSet` (re-runnable) that peeks the auto-derived change
  address; commit it with `commit_change` (reveal + mark used) when you use the
  tx, or ignore it on abandon. The caller supplies the RNG. Emit the PSBT
  directly via `bdk_tx::TxTemplate::build_psbt`.
- `add_global_xpubs` fills the PSBT's global xpubs (the only emission step that
  needs the wallet).

Ported from the bdk_wallet#502 PoC, re-expressed over the integrated bdk_tx API
and the wallet's public accessors. MTP is faked from the confirmation block
time; UTXO locking is honored; `longterm_feerate` lives on `SelectParams` and
feeds the waste-aware change policy for every strategy. End-to-end tests cover
the pipeline, candidate filtering, change commit, and error paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
evanlinjin added a commit to evanlinjin/bdk-tx that referenced this pull request Jun 27, 2026
Bridge between bdk_wallet and bdk_tx, exposed as a `WalletTxExt` extension
trait on `bdk_wallet::Wallet`. Keeping it in its own crate means neither base
crate depends on the other: `bdk_wallet` stays stable, `bdk_tx` stays free to
move, and the bridge absorbs the coupling (the decoupling argument from
bitcoindevkit/bdk_wallet#297).

Three-stage pipeline:
- `candidates`/`candidates_with`/`rbf_candidates` -> `CandidateSet` (stage 1).
- `select` -> `(TxTemplate, Option<AddressInfo>)` (stage 2): a pure read over a
  borrowed `&CandidateSet` (re-runnable) that peeks the auto-derived change
  address; commit it with `commit_change` (reveal + mark used) when you use the
  tx, or ignore it on abandon. The caller supplies the RNG. Emit the PSBT
  directly via `bdk_tx::TxTemplate::build_psbt`.
- `add_global_xpubs` fills the PSBT's global xpubs (the only emission step that
  needs the wallet).

Ported from the bdk_wallet#502 PoC, re-expressed over the integrated bdk_tx API
and the wallet's public accessors. MTP is faked from the confirmation block
time; UTXO locking is honored; `longterm_feerate` lives on `SelectParams` and
feeds the waste-aware change policy for every strategy. End-to-end tests cover
the pipeline, candidate filtering, change commit, and error paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
evanlinjin added a commit to evanlinjin/bdk-tx that referenced this pull request Jun 27, 2026
Bridge between bdk_wallet and bdk_tx, exposed as a `WalletTxExt` extension
trait on `bdk_wallet::Wallet`. Keeping it in its own crate means neither base
crate depends on the other: `bdk_wallet` stays stable, `bdk_tx` stays free to
move, and the bridge absorbs the coupling (the decoupling argument from
bitcoindevkit/bdk_wallet#297).

Three-stage pipeline:
- `candidates`/`candidates_with`/`rbf_candidates` -> `CandidateSet` (stage 1).
- `select` -> `(TxTemplate, Option<AddressInfo>)` (stage 2): a pure read over a
  borrowed `&CandidateSet` (re-runnable) that peeks the auto-derived change
  address; commit it with `commit_change` (reveal + mark used) when you use the
  tx, or ignore it on abandon. The caller supplies the RNG. Emit the PSBT
  directly via `bdk_tx::TxTemplate::build_psbt`.
- `add_global_xpubs` fills the PSBT's global xpubs (the only emission step that
  needs the wallet).

Ported from the bdk_wallet#502 PoC, re-expressed over the integrated bdk_tx API
and the wallet's public accessors. MTP is faked from the confirmation block
time; UTXO locking is honored; `longterm_feerate` lives on `SelectParams` and
feeds the waste-aware change policy for every strategy. End-to-end tests cover
the pipeline, candidate filtering, change commit, and error paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
evanlinjin added a commit to evanlinjin/bdk-tx that referenced this pull request Jun 27, 2026
Bridge between bdk_wallet and bdk_tx, exposed as a `WalletTxExt` extension
trait on `bdk_wallet::Wallet`. Keeping it in its own crate means neither base
crate depends on the other: `bdk_wallet` stays stable, `bdk_tx` stays free to
move, and the bridge absorbs the coupling (the decoupling argument from
bitcoindevkit/bdk_wallet#297).

Three-stage pipeline:
- `candidates`/`candidates_with`/`rbf_candidates` -> `CandidateSet` (stage 1).
- `select` -> `(TxTemplate, Option<AddressInfo>)` (stage 2): a pure read over a
  borrowed `&CandidateSet` (re-runnable) that peeks the auto-derived change
  address; commit it with `commit_change` (reveal + mark used) when you use the
  tx, or ignore it on abandon. The caller supplies the RNG. Emit the PSBT
  directly via `bdk_tx::TxTemplate::build_psbt`.
- `add_global_xpubs` fills the PSBT's global xpubs (the only emission step that
  needs the wallet).

Ported from the bdk_wallet#502 PoC, re-expressed over the integrated bdk_tx API
and the wallet's public accessors. MTP is faked from the confirmation block
time; UTXO locking is honored; `longterm_feerate` lives on `SelectParams` and
feeds the waste-aware change policy for every strategy. End-to-end tests cover
the pipeline, candidate filtering, change commit, and error paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
evanlinjin added a commit to evanlinjin/bdk-tx that referenced this pull request Jun 27, 2026
Bridge between bdk_wallet and bdk_tx, exposed as a `WalletTxExt` extension
trait on `bdk_wallet::Wallet`. Keeping it in its own crate means neither base
crate depends on the other: `bdk_wallet` stays stable, `bdk_tx` stays free to
move, and the bridge absorbs the coupling (the decoupling argument from
bitcoindevkit/bdk_wallet#297).

Three-stage pipeline:
- `candidates`/`candidates_with`/`rbf_candidates` -> `CandidateSet` (stage 1).
- `select` -> `(TxTemplate, Option<AddressInfo>)` (stage 2): a pure read over a
  borrowed `&CandidateSet` (re-runnable) that peeks the auto-derived change
  address; commit it with `commit_change` (reveal + mark used) when you use the
  tx, or ignore it on abandon. The caller supplies the RNG. Emit the PSBT
  directly via `bdk_tx::TxTemplate::build_psbt`.
- `add_global_xpubs` fills the PSBT's global xpubs (the only emission step that
  needs the wallet).

Ported from the bdk_wallet#502 PoC, re-expressed over the integrated bdk_tx API
and the wallet's public accessors. MTP is faked from the confirmation block
time; UTXO locking is honored; `longterm_feerate` lives on `SelectParams` and
feeds the waste-aware change policy for every strategy. End-to-end tests cover
the pipeline, candidate filtering, change commit, and error paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
evanlinjin added a commit to evanlinjin/bdk-tx that referenced this pull request Jun 28, 2026
Bridge between bdk_wallet and bdk_tx, exposed as a `WalletTxExt` extension
trait on `bdk_wallet::Wallet`. Keeping it in its own crate means neither base
crate depends on the other: `bdk_wallet` stays stable, `bdk_tx` stays free to
move, and the bridge absorbs the coupling (the decoupling argument from
bitcoindevkit/bdk_wallet#297).

Three-stage pipeline:
- `candidates`/`candidates_with`/`rbf_candidates` -> `CandidateSet` (stage 1).
- `select` -> `(TxTemplate, Option<AddressInfo>)` (stage 2): a pure read over a
  borrowed `&CandidateSet` (re-runnable) that peeks the auto-derived change
  address; commit it with `commit_change` (reveal + mark used) when you use the
  tx, or ignore it on abandon. The caller supplies the RNG. Emit the PSBT
  directly via `bdk_tx::TxTemplate::build_psbt`.
- `add_global_xpubs` fills the PSBT's global xpubs (the only emission step that
  needs the wallet).

Ported from the bdk_wallet#502 PoC, re-expressed over the integrated bdk_tx API
and the wallet's public accessors. MTP is faked from the confirmation block
time; UTXO locking is honored; `longterm_feerate` lives on `SelectParams` and
feeds the waste-aware change policy for every strategy. End-to-end tests cover
the pipeline, candidate filtering, change commit, and error paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
evanlinjin added a commit to evanlinjin/bdk-tx that referenced this pull request Jun 28, 2026
Bridge between bdk_wallet and bdk_tx, exposed as a `WalletTxExt` extension
trait on `bdk_wallet::Wallet`. Keeping it in its own crate means neither base
crate depends on the other: `bdk_wallet` stays stable, `bdk_tx` stays free to
move, and the bridge absorbs the coupling (the decoupling argument from
bitcoindevkit/bdk_wallet#297).

Three-stage pipeline:
- `candidates`/`candidates_with`/`rbf_candidates` -> `CandidateSet` (stage 1).
- `select` -> `(TxTemplate, Option<AddressInfo>)` (stage 2): a pure read over a
  borrowed `&CandidateSet` (re-runnable) that peeks the auto-derived change
  address; commit it with `commit_change` (reveal + mark used) when you use the
  tx, or ignore it on abandon. The caller supplies the RNG. Emit the PSBT
  directly via `bdk_tx::TxTemplate::build_psbt`.
- `add_global_xpubs` fills the PSBT's global xpubs (the only emission step that
  needs the wallet).

Ported from the bdk_wallet#502 PoC, re-expressed over the integrated bdk_tx API
and the wallet's public accessors. MTP is faked from the confirmation block
time; UTXO locking is honored; `longterm_feerate` lives on `SelectParams` and
feeds the waste-aware change policy for every strategy. End-to-end tests cover
the pipeline, candidate filtering, change commit, and error paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread src/wallet/error.rs
Comment on lines +433 to +434
/// One of the transactions to be replaced is already confirmed
TransactionConfirmed(Txid),

@evanlinjin evanlinjin Jun 28, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this error variant earns it's keep.

  • Most callers would want to check whether the transaction is still unconfirmed before trying to replace it. A caller that doesn't do that obviously wants to create a transaction that conflicts with a confirmed one.

  • The guard is partial. It only catches "already confirmed at build time". The original transaction can be confirmed before the replacement is ready to broadcast.

evanlinjin added a commit to evanlinjin/bdk-tx that referenced this pull request Jun 28, 2026
Bridge between bdk_wallet and bdk_tx, exposed as a `WalletTxExt` extension
trait on `bdk_wallet::Wallet`. Keeping it in its own crate means neither base
crate depends on the other: `bdk_wallet` stays stable, `bdk_tx` stays free to
move, and the bridge absorbs the coupling (the decoupling argument from
bitcoindevkit/bdk_wallet#297).

Three-stage pipeline:
- `candidates`/`candidates_with`/`rbf_candidates` -> `CandidateSet` (stage 1).
- `select` -> `(TxTemplate, Option<AddressInfo>)` (stage 2): a pure read over a
  borrowed `&CandidateSet` (re-runnable) that peeks the auto-derived change
  address; commit it with `commit_change` (reveal + mark used) when you use the
  tx, or ignore it on abandon. The caller supplies the RNG. Emit the PSBT
  directly via `bdk_tx::TxTemplate::build_psbt`.
- `add_global_xpubs` fills the PSBT's global xpubs (the only emission step that
  needs the wallet).

Ported from the bdk_wallet#502 PoC, re-expressed over the integrated bdk_tx API
and the wallet's public accessors. MTP is faked from the confirmation block
time; UTXO locking is honored; `longterm_feerate` lives on `SelectParams` and
feeds the waste-aware change policy for every strategy. End-to-end tests cover
the pipeline, candidate filtering, change commit, and error paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
evanlinjin added a commit to evanlinjin/bdk-tx that referenced this pull request Jun 28, 2026
Bridge between bdk_wallet and bdk_tx, exposed as a `WalletTxExt` extension
trait on `bdk_wallet::Wallet`. Keeping it in its own crate means neither base
crate depends on the other: `bdk_wallet` stays stable, `bdk_tx` stays free to
move, and the bridge absorbs the coupling (the decoupling argument from
bitcoindevkit/bdk_wallet#297).

Three-stage pipeline:
- `candidates`/`candidates_with`/`rbf_candidates` -> `CandidateSet` (stage 1).
- `select` -> `(TxTemplate, Option<AddressInfo>)` (stage 2): a pure read over a
  borrowed `&CandidateSet` (re-runnable) that peeks the auto-derived change
  address; commit it with `commit_change` (reveal + mark used) when you use the
  tx, or ignore it on abandon. The caller supplies the RNG. Emit the PSBT
  directly via `bdk_tx::TxTemplate::build_psbt`.
- `add_global_xpubs` fills the PSBT's global xpubs (the only emission step that
  needs the wallet).

Ported from the bdk_wallet#502 PoC, re-expressed over the integrated bdk_tx API
and the wallet's public accessors. MTP is faked from the confirmation block
time; UTXO locking is honored; `longterm_feerate` lives on `SelectParams` and
feeds the waste-aware change policy for every strategy. End-to-end tests cover
the pipeline, candidate filtering, change commit, and error paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
evanlinjin added a commit to evanlinjin/bdk-tx that referenced this pull request Jun 28, 2026
Bridge between bdk_wallet and bdk_tx, exposed as a `WalletTxExt` extension
trait on `bdk_wallet::Wallet`. Keeping it in its own crate means neither base
crate depends on the other: `bdk_wallet` stays stable, `bdk_tx` stays free to
move, and the bridge absorbs the coupling (the decoupling argument from
bitcoindevkit/bdk_wallet#297).

Three-stage pipeline:
- `candidates`/`candidates_with`/`rbf_candidates` -> `CandidateSet` (stage 1).
- `select` -> `(TxTemplate, Option<AddressInfo>)` (stage 2): a pure read over a
  borrowed `&CandidateSet` (re-runnable) that peeks the auto-derived change
  address; commit it with `commit_change` (reveal + mark used) when you use the
  tx, or ignore it on abandon. The caller supplies the RNG. Emit the PSBT
  directly via `bdk_tx::TxTemplate::build_psbt`.
- `add_global_xpubs` fills the PSBT's global xpubs (the only emission step that
  needs the wallet).

Ported from the bdk_wallet#502 PoC, re-expressed over the integrated bdk_tx API
and the wallet's public accessors. MTP is faked from the confirmation block
time; UTXO locking is honored; `longterm_feerate` lives on `SelectParams` and
feeds the waste-aware change policy for every strategy. End-to-end tests cover
the pipeline, candidate filtering, change commit, and error paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
evanlinjin added a commit to evanlinjin/bdk-tx that referenced this pull request Jun 28, 2026
Bridge between bdk_wallet and bdk_tx, exposed as a `WalletTxExt` extension
trait on `bdk_wallet::Wallet`. Keeping it in its own crate means neither base
crate depends on the other: `bdk_wallet` stays stable, `bdk_tx` stays free to
move, and the bridge absorbs the coupling (the decoupling argument from
bitcoindevkit/bdk_wallet#297).

Three-stage pipeline:
- `candidates`/`candidates_with`/`rbf_candidates` -> `CandidateSet` (stage 1).
- `select` -> `(TxTemplate, Option<AddressInfo>)` (stage 2): a pure read over a
  borrowed `&CandidateSet` (re-runnable) that peeks the auto-derived change
  address; commit it with `commit_change` (reveal + mark used) when you use the
  tx, or ignore it on abandon. The caller supplies the RNG. Emit the PSBT
  directly via `bdk_tx::TxTemplate::build_psbt`.
- `add_global_xpubs` fills the PSBT's global xpubs (the only emission step that
  needs the wallet).

Ported from the bdk_wallet#502 PoC, re-expressed over the integrated bdk_tx API
and the wallet's public accessors. MTP is faked from the confirmation block
time; UTXO locking is honored; `longterm_feerate` lives on `SelectParams` and
feeds the waste-aware change policy for every strategy. End-to-end tests cover
the pipeline, candidate filtering, change commit, and error paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
evanlinjin added a commit to evanlinjin/bdk-tx that referenced this pull request Jun 30, 2026
Bridge between bdk_wallet and bdk_tx, exposed as a `WalletTxExt` extension
trait on `bdk_wallet::Wallet`. Keeping it in its own crate means neither base
crate depends on the other: `bdk_wallet` stays stable, `bdk_tx` stays free to
move, and the bridge absorbs the coupling (the decoupling argument from
bitcoindevkit/bdk_wallet#297).

Three-stage pipeline:
- `candidates`/`candidates_with`/`rbf_candidates` -> `CandidateSet` (stage 1).
- `select` -> `(TxTemplate, Option<AddressInfo>)` (stage 2): a pure read over a
  borrowed `&CandidateSet` (re-runnable) that peeks the auto-derived change
  address; commit it with `commit_change` (reveal + mark used) when you use the
  tx, or ignore it on abandon. The caller supplies the RNG. Emit the PSBT
  directly via `bdk_tx::TxTemplate::build_psbt`.
- `add_global_xpubs` fills the PSBT's global xpubs (the only emission step that
  needs the wallet).

Ported from the bdk_wallet#502 PoC, re-expressed over the integrated bdk_tx API
and the wallet's public accessors. MTP is faked from the confirmation block
time; UTXO locking is honored; `longterm_feerate` lives on `SelectParams` and
feeds the waste-aware change policy for every strategy. End-to-end tests cover
the pipeline, candidate filtering, change commit, and error paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
evanlinjin added a commit to evanlinjin/bdk-tx that referenced this pull request Jun 30, 2026
Bridge between bdk_wallet and bdk_tx, exposed as a `WalletTxExt` extension
trait on `bdk_wallet::Wallet`. Keeping it in its own crate means neither base
crate depends on the other: `bdk_wallet` stays stable, `bdk_tx` stays free to
move, and the bridge absorbs the coupling (the decoupling argument from
bitcoindevkit/bdk_wallet#297).

Three-stage pipeline:
- `candidates`/`candidates_with`/`rbf_candidates` -> `CandidateSet` (stage 1).
- `select` -> `(TxTemplate, Option<AddressInfo>)` (stage 2): a pure read over a
  borrowed `&CandidateSet` (re-runnable) that peeks the auto-derived change
  address; commit it with `commit_change` (reveal + mark used) when you use the
  tx, or ignore it on abandon. The caller supplies the RNG. Emit the PSBT
  directly via `bdk_tx::TxTemplate::build_psbt`.
- `add_global_xpubs` fills the PSBT's global xpubs (the only emission step that
  needs the wallet).

Ported from the bdk_wallet#502 PoC, re-expressed over the integrated bdk_tx API
and the wallet's public accessors. MTP is faked from the confirmation block
time; UTXO locking is honored; `longterm_feerate` lives on `SelectParams` and
feeds the waste-aware change policy for every strategy. End-to-end tests cover
the pipeline, candidate filtering, change commit, and error paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
evanlinjin added a commit to evanlinjin/bdk-tx that referenced this pull request Jun 30, 2026
Bridge between bdk_wallet and bdk_tx, exposed as a `WalletTxExt` extension
trait on `bdk_wallet::Wallet`. Keeping it in its own crate means neither base
crate depends on the other: `bdk_wallet` stays stable, `bdk_tx` stays free to
move, and the bridge absorbs the coupling (the decoupling argument from
bitcoindevkit/bdk_wallet#297).

Three-stage pipeline:
- `candidates`/`candidates_with`/`rbf_candidates` -> `CandidateSet` (stage 1).
- `select` -> `(TxTemplate, Option<AddressInfo>)` (stage 2): a pure read over a
  borrowed `&CandidateSet` (re-runnable) that peeks the auto-derived change
  address; commit it with `commit_change` (reveal + mark used) when you use the
  tx, or ignore it on abandon. The caller supplies the RNG. Emit the PSBT
  directly via `bdk_tx::TxTemplate::build_psbt`.
- `add_global_xpubs` fills the PSBT's global xpubs (the only emission step that
  needs the wallet).

Ported from the bdk_wallet#502 PoC, re-expressed over the integrated bdk_tx API
and the wallet's public accessors. MTP is faked from the confirmation block
time; UTXO locking is honored; `longterm_feerate` lives on `SelectParams` and
feeds the waste-aware change policy for every strategy. End-to-end tests cover
the pipeline, candidate filtering, change commit, and error paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@bitcoindevkit bitcoindevkit locked as too heated and limited conversation to collaborators Jun 30, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

new feature New feature or request

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

Flexible RBF construction