<!-- You can erase any parts of this template not applicable to your Pull Request. -->
### Description
<!-- Describe the purpose of this PR, what's being adding and/or fixed -->
This PR updates the Wallet API to v3.1.0 and adds wallet subcommands to lock and unlock UTXOs. Locked outpoints are excluded from coin selection, and the lock state is stored in the wallet. It also updates the `bdk_redb` to v0.2.0 and `bdk_kyoto` to v0.17.0.
Fixes #293 and builds upon #289 and #278
### Notes to the reviewers
<!-- In this section you can include notes directed to the reviewers, like explaining why some parts
of the PR were done in a specific way -->
## Changelog notice
<!-- Notice the release manager should include in the release tag message changelog -->
<!-- See https://keepachangelog.com/en/1.0.0/ for examples -->
- Update bdk_wallet to v3.1.0
- Add wallet `lock_utxo` command
- Add wallet `unlock_utxo` command
- Add wallet `locked_uxtos` command
- Update bdk_redb to v0.2.0
- Update bdk_kyoto to v0.17.0
- Replace `Network` enum with `NetworkKind`
- Replace `include_output_redeem_witness_script` with `add_global_xpubs` in TxBuilder
- Replace `submit_package` with `broadcast_random` for broadcasting transactions in KyotoClient
### Checklists
#### All Submissions:
* [x] I've signed all my commits
* [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk-cli/blob/master/CONTRIBUTING.md)
* [x] I ran `cargo fmt` and `cargo clippy` before committing
#### New Features:
* [ ] I've added tests for the new feature
* [ ] I've added docs for the new feature
* [ ] I've updated `CHANGELOG.md`
<!-- You can erase any parts of this template not applicable to your Pull Request. -->
### Description
The README referenced outdated cargo feature flags `kyoto` and `sp`, which will cause build failures for users following the instructions. This commit updates the documentation to use the correct flags `cbf` and `silent-payments` as defined in the current `Cargo.toml`.
Fixes #299
### Notes to the reviewers
This is a documentation update to the `README.md`. I specifically left the reference to `Kyoto` in the "About" section intact, as it correctly refers to the underlying `bdk_kyoto` library/concept, and only updated the actual Cargo feature flags in the code blocks and feature lists.
## Changelog notice
* Fixed outdated cargo feature flags (`kyoto` -> `cbf` and `sp` -> `silent-payments`) in the README instructions.
### Checklists
#### All Submissions:
* [x] I've signed all my commits
* [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk-cli/blob/master/CONTRIBUTING.md)
* [x] I ran `cargo fmt` and `cargo clippy` before committing
#### Bugfixes:
* [ ] This pull request breaks the existing API
* [ ] I've added tests to reproduce the issue which are now passing
* [x] I'm linking the issue being fixed by this PR
docs: update cargo feature flags in README to match Cargo.toml
The README referenced outdated compile-time feature flags `kyoto` and `sp`, which caused build failures for users following the instructions. This commit updates the documentation to use the correct flags `cbf` and `silent-payments` as defined in the current Cargo.toml.
<!-- You can erase any parts of this template not applicable to your Pull Request. -->
### Description
<!-- Describe the purpose of this PR, what's being adding and/or fixed -->
This PR builds on #278 and introduces integration tests for bdk-cli. It replaces manual `std::process::Command` boilerplate with the `assert_cmd` library, allowing us to perform black-box testing against the compiled binary.
<!-- In this section you can include notes directed to the reviewers, like explaining why some parts
of the PR were done in a specific way -->
## Changelog notice
<!-- Notice the release manager should include in the release tag message changelog -->
<!-- See https://keepachangelog.com/en/1.0.0/ for examples -->
- Introduces the BdkCli helper struct to inject context state into base commands.
- Dropped `verbose` flag from wallets as it was applicable to only `Pbst`
### Checklists
#### All Submissions:
* [x] I've signed all my commits
* [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk-cli/blob/master/CONTRIBUTING.md)
* [x] I ran `cargo fmt` and `cargo clippy` before committing
- The problem: When running `cargo test --all-
features`, the backends (electrum, rpc, esplora
from TestEnv) run in parallel at the number of
cpus available and exhaust the processes/ports
available, thereby resulting in os error 35.
This fix limits the number of threads that are
available for the tests to run in parallel.
<!-- You can erase any parts of this template not applicable to your Pull Request. -->
### Description
This PR restructures the bdk-cli codebase to move away from a monolithic handling model towards a modular architecture. The primary goal is to improve code readability, simplify the addition of new features, and decouple core logic into smaller modules.
Fixes #273
<!-- Describe the purpose of this PR, what's being adding and/or fixed -->
### Notes to the reviewers
While trying to achieve the above-stated goal, I took maximum care to avoid introducing new bugs. As a result, the existing execution logic was preserved as much as possible.
<!-- In this section you can include notes directed to the reviewers, like explaining why some parts
of the PR were done in a specific way -->
This PR introduces two new subdirectories under `src`:
- handlers: This contains all the subcommands' execution logic grouped logically according to the top-level commands. Modules include the `config`, `descriptor`, `key`, `offline`, `online` and `repl` modules. They each contain structures for the subcommand, execution logic, and implementation of the top-level enum.
- utils: This subdirectory contains helper functions used across the app. They are also grouped logically according to related functionality. So far, we have the descriptor-related module, the output that formats responses, and the `types` module that defines response structures.
**Other notable changes**
- main module is retained with added functionality of routing requests to the right module for execution.
- All client-related functionalities have been moved from various modules into the `client` module, and it defines the enum that holds all the available clients, as well as implements the functionalities such as broadcasting transactions and syncing operations.
- The `AppCommand` trait that defines how each subcommand should be structured and the `execute` method they should implement.
- The `AppContext` struct that holds the universal parameters that subcommands may need. Each subcommand's `execute` method accepts this struct and uses the params for its execution.
- The output module in the util subdirectory attempts to present a uniform presentation layer by having an output trait, the `FormatOutput` trait, which is implemented by all `types` presenting data response to the user.
- Collapsed the `wallet` subdirectory into the `persister` module that defines all structures and functionalities related to persistence.
- Introduced a type state pattern for the AppContext: To minimise runtime errors, the `Init`, `OfflineOperations` and `OnlineOperations` state structs were introduced, and AppContext is generic over these states. This moved the validation from runtime to compile time.
- Introduced `FormatOutput::write_out` and made it generic over the Write trait to allow for flexibility in testing
- Extracted all initialisation logic (database, config loading and persistence initialisation) into `runtime` module. Also, added the `RuntimeWallet` enum to return options of a persisted wallet and a standard non-persisted wallet. The WalletRuntime struct is a wrapper that determines the type of wallet needed and initialises it and handles loading of a wallet from config.
**Request-Response Cycle**
The following outlines how requests are handled and responses are generated after introducing changes to the structure:
1. When a user enters a set of commands, those commands are received and parsed by the Clap library into Rust structures, such as `CliOpts`, `WalletOpts`, and subcommands. This process takes place in the `commands` module.
2. The parsed request is then passed to the `main` module. The main module uses the `runtime` module to interpret the request and initialize any necessary resources (such as wallets, databases, and clients) needed to fulfill the request. It then routes the request to the appropriate handler for execution.
3. Once a particular handler receives the request along with all the required resources, it processes the specific command using the `AppContext` and prepares a response.
4. After processing is complete, the handler calls the `output` module to format the result, serialize it into JSON, and return it to the terminal.
## Changelog notice
- In the `key derive` subcommand, when printing help message, the clap arg for env=“PATH” often pull all system and displays all system paths. This has been changed to derivation_path I.e. env=“DERIVATION_PATH” to prevent clap from picking the system paths and rendering it
- Moved the wallet subdirectory that served as persister into the persister module
- Moved DatabaseType enum from commands module into persister module
- Removed the —pretty flag
<!-- Notice the release manager should include in the release tag message changelog -->
<!-- See https://keepachangelog.com/en/1.0.0/ for examples -->
### Checklists
#### All Submissions:
* [x] I've signed all my commits
* [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk-cli/blob/master/CONTRIBUTING.md)
* [x] I ran `cargo fmt` and `cargo clippy` before committing
<!-- You can erase any parts of this template not applicable to your Pull Request. -->
### Description
This PR adds support for BIP353 payment instructions.
The following notable changes are done:
- Adding of an option `resolve_dns_recipient` which receives a Human Readable Name (HRN) and returns the associated address
- Modify the `create_tx` for it to support user specifying recipients as `HRN`.
### Notes to the reviewers
<!-- In this section you can include notes directed to the reviewers, like explaining why some parts
of the PR were done in a specific way -->
Here is a list of HRN that could be used to test the implementation:
- pay@dunxen.dev: Supports BOLT 12 Payment method only (CAUTION: mainnet)
- send.some@satsto.me: Supports BOLT 12 payment and On Chain (CAUTION: mainnet)
- Testing resolving: `bdk-cli -n testnet resolve_dns_recipient testnet@bitdevsyde.org`
- Testing create tx: `bdk-cli -n testnet wallet -w regtest_default_wallet create_tx --to "bcrt1qe497k549sgw9trzym50tdlegq3xx4apjqynjqm:1000" --to_dns "testnet@bitdevsyde.org:5000"`
## Changelog notice
<!-- Notice the release manager should include in the release tag message changelog -->
<!-- See https://keepachangelog.com/en/1.0.0/ for examples -->
- Add top level command `resolve_dns_recipient` to resolve the DNS payment instructions
- Add option `--to_dns` to `create_tx` command to allow sending to a Human Readable Name (HRN)
### Checklists
#### All Submissions:
* [x] I've signed all my commits
* [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk-cli/blob/master/CONTRIBUTING.md)
* [x] I ran `cargo fmt` and `cargo clippy` before committing
#### New Features:
* [ ] I've added tests for the new feature
* [ ] I've added docs for the new feature
* [ ] I've updated `CHANGELOG.md`
### Description
https://github.com/bitcoindevkit/bdk-cli/pull/230 needed to be merged for this to go through
Address https://github.com/bitcoindevkit/bdk-cli/issues/149 also follow up to #200
This PR adds persistance to existing async payjoin integration
This introduces neccessary database model and tables also add commad for resume to allow interrupted sessions to be continued also a particular session either send or receive.
A history commad to view payjoin history and status has been added
### Notes to the reviewers
Step to review this include making a payjoin transaction
Run a receiver to get a BIP21 URI then pass it to the sender as seen in docs https://github.com/bitcoindevkit/bdk-cli/blob/b9cf2acc5f10db46fa30777ff0910b8610a5fc33/README.md?plain=1#L121-L141
To test resumption, interrupt either side with Ctrl+C mid-session then run resume on that side to continue. A few scenarios worth covering: receiver resuming after interrupt and sender resuming after interrupt. Use history after each scenario to confirm the session state was persisted correctly.
* [x] I've signed all my commits
* [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk-cli/blob/master/CONTRIBUTING.md)
* [x] I ran `cargo fmt` and `cargo clippy` before committing
#### New Features:
* [x] I've added docs for the new feature
Mshehu5 [Sun, 28 Jun 2026 16:01:25 +0000 (17:01 +0100)]
Retry Payjoin requests with other relays
Payjoin currently keeps using the relay selected during OHTTP key
bootstrapping. If that relay goes offline, the session fails even when
other relay URLs were supplied.
Select from the available relays for each OHTTP request and remember
failures for the rest of the command. Build a fresh request for every
attempt so failover does not reuse linkable OHTTP ciphertext.
chore(deps): Bump payjoin and enable reqwest rustls
Move to payjoin 0.25.0 to stay closer to the latest release.
Enable rustls for the direct reqwest client because Payjoin
polling uses bdk-cli's own HTTPS client and without a TLS
backend the first relay poll fails.
Refine the skipped monitoring status message for the receiver
flow.
Mshehu5 [Mon, 16 Feb 2026 13:51:18 +0000 (14:51 +0100)]
Document payjoin recovery commands and SQLite setup
Update the README to cover the new `resume` and `history` commands
so users can recover interrupted payjoin sessions and inspect saved
session state. Also add the SQLite dependency needed for the
payjoin persistence workflow.
This keeps the user-facing setup and command documentation aligned
with the new persistence and recovery behavior.
Mshehu5 [Mon, 16 Feb 2026 13:50:06 +0000 (14:50 +0100)]
Add commands to resume and view payjoin history
Expose persisted payjoin session state through CLI commands so users
can recover interrupted sessions and review prior session progress.
Add `resume` to continue pending sender and receiver sessions,
`history` to list saved sessions, status text helpers for clearer
output, and session ID filtering to target a specific session.
This improves recovery and troubleshooting for long-running async
payjoin flows by making persisted session state available from the
CLI.
Mshehu5 [Mon, 16 Feb 2026 13:48:33 +0000 (14:48 +0100)]
Integrate payjoin session persistence into workflow
Wire the payjoin persistence layer into the existing send and receive
flows so session state is saved during normal operation and can be
replayed later. Initialize the database from the handlers, replace
the noop persisters with SQLite-backed persisters, resume existing
sessions, and record seen inputs in the receiver flow for replay
protection.
This moves persistence from a standalone storage layer into the
runtime payjoin workflow so interrupted sessions can continue from
saved state instead of starting over. It also simplifies error
handling by relying on `?` once the storage errors map cleanly into
the CLI error type.
Mshehu5 [Mon, 16 Feb 2026 13:31:08 +0000 (14:31 +0100)]
Add SQLite backing store for payjoin sessions
Persist payjoin sender and receiver state in SQLite so interrupted
payjoin sessions can be resumed after the CLI exits. Add dedicated
tables for send and receive sessions, append-only event logs for
state replay, receiver pubkey lookup for sender sessions, and
seen-input tracking for replay protection.
This follows the intended async payjoin design by persisting session
state across interruptions. SQLite keeps the initial persistence
backend simple and builds on existing rusqlite support, at the cost
of a small payjoin-specific schema and serialization layer.
<!-- You can erase any parts of this template not applicable to your Pull Request. -->
### Description
This PR updates the Wallet API to v2.4.0 and other dependencies. It also adds WalletEvent to both sync and full_scan for all backends.
Fixes #243
<!-- Describe the purpose of this PR, what's being adding and/or fixed -->
## Changelog notice
- Update bdk_wallet to v2.4.0
- Add WalletEvents to all backends Esplora, Electrum, Rpc and CBF.
- Add `print_wallet_events` function to print wallet events to the terminal during sync
- Update bdk_bitcoind_rpc to v0.22.0
- Update bdk_electrum to v0.24.0
- Update bdk_kyoto to v0.15.4
- Update bdk_esplora to v0.22.2
<!-- Notice the release manager should include in the release tag message changelog -->
<!-- See https://keepachangelog.com/en/1.0.0/ for examples -->
### Checklists
#### All Submissions:
* [x] I've signed all my commits
* [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk-cli/blob/master/CONTRIBUTING.md)
* [x] I ran `cargo fmt` and `cargo clippy` before committing
Previously, passing multiple `--to` arguments with `--send_all` would silently drain the wallet to only the first recipient, ignoring the rest. This was inconsistent with the silent-payments `create_tx`, which already validates the recipient count.
Now returns an error unless exactly one recipient is provided.
### Notes to the reviewers
- The fix mirrors the validation logic already present in the silent-payments `create_tx` branch of the same file, so behavior is now consistent between the two code paths.
## Changelog notice
- Fixed create_tx --send_all to reject multiple recipients instead of silently using only the first one
### Checklists
#### All Submissions:
* [x] I've signed all my commits
* [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk-cli/blob/master/CONTRIBUTING.md)
* [x] I ran `cargo fmt` and `cargo clippy` before committing
* [x] I've updated `CHANGELOG.md`
#### Bugfixes:
* [ ] This pull request breaks the existing API
* [ ] I've added tests to reproduce the issue which are now passing
* [x] I'm linking the issue being fixed by this PR
Implements randomization of the unspendable internal key for taproot descriptors. This is the first part of #218, which consists of two parts:
1. **This PR**: Randomize unspendable internal key for taproot descriptor
2. **Follow-up**: Add verification command to ensure internal key is derived from NUMS key
Split into separate PRs for easier review and iteration, and to allow independent discussion of the verification command implementation, as one of the possible approaches could introduce breaking changes.
### Notes to the reviewers
The `compile` command now returns an additional `r` field for taproot descriptors (`-t tr`), containing the randomly generated internal key. Each compilation will produce a different internal key instead of using a fixed NUMS key.
Other descriptor types remain unchanged:
```
-> % bdk-cli compile "pk(A)" -t sh
{
"descriptor": "sh(pk(A))#k80zhe7s"
}
```
### Checklists
#### All Submissions:
* [x] I've signed all my commits
* [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk-cli/blob/master/CONTRIBUTING.md)
* [x] I ran `cargo fmt` and `cargo clippy` before committing
#### New Features:
* [x] I've added tests for the new feature
* [ ] I've added docs for the new feature
* [ ] I've updated `CHANGELOG.md`
Artemiy [Sun, 21 Jun 2026 07:11:17 +0000 (10:11 +0300)]
fix(create_tx): enforce single recipient for send_all
Previously, passing multiple --to arguments with --send_all would
silently drain the wallet to only the first recipient, ignoring the
rest. This was inconsistent with the silent-payments create_tx, which
already validates the recipient count.
Now returns an error unless exactly one recipient is provided
Vihiga Tyonum [Mon, 22 Jun 2026 15:07:28 +0000 (16:07 +0100)]
refactor(runtime): Add address and createtx to db
- Add new address, unused address and createtx
commands to list of commands that require
loading existing db
- adding persisting changes in offline and online
commands
Vihiga Tyonum [Fri, 29 May 2026 03:17:56 +0000 (04:17 +0100)]
Refactor(handlers): Define app context states
- Define Init state for when an execution does
not need either the wallet or client for execution
- Define the Offline wallet operations state
for app context when an execution envt needs
a wallet
- Define the online wallet operations state for
appcontext when an execution needs both the
wallet and client
- make app context generic over the state
- make the app command and async app command
generic over the execution context
- deleted shorten fn as it was applicable to the
pretty flag
- removed tests for pretty flag
Vadim Anufriev [Tue, 24 Mar 2026 20:12:30 +0000 (00:12 +0400)]
refactor(compile): lazy compilation and use pipe for readability
Move miniscript compilation inside match arms to avoid compiling
for all script contexts when only one is needed. Use `tap::Pipe`
for concise method chaining in sh/wsh/sh-wsh branches.