bitcoindevkit / bitcoindevkit/bdk_wallet

Spending P2A Output with a Non-Zero Value can Return CreateTxError::CoinSelection

Open
#376 4 comments 1 reaction 0 assignees View on GitHub
bug
Dominant language
Rust
Stars
59
Forks
105
Avg merge
10d 9h
Merged PRs (30d)
1

Description

**Describe the bug**
We use BDK as our onchain wallet for the Bark project, an important part of that is using BDK to spend P2A outputs when users perform an emergency exit. Each "exit transaction" contains a P2A output, typically with a value of zero sats, but sometimes with a non-zero value due to how we manage fees for certain operations. When the P2A value is zero there's no problem, however when it's non-zero you can run into edge cases which result in unexpected errors.

Here's an example scenario:
- The wallet has 1 UTXO of 1,000,000 sats
- We try to create a new transaction to spend the P2A output of an exit transaction which isn't contained in the wallet itself
- We add a `drain_to` address which is the BDK wallet
- We set `absolute_fee` to 200 sats (enough to broadcast the exit transaction and the transaction we're constructing as a TRUC package)
- If the P2A output has a value of 0:
- BDK will pull in the 1,000,000 sat UTXO and drain to a wallet address with a 999,800 sat output
- This is as expected
- If the P2A output has a value of 1,000:
- BDK won't use any extra UTXOs and will drain to a wallet address with a 800 sat output
- This is as expected
- If the P2A output has a value of 500:
- BDK won't use any extra UTXOs and will error because it can't create a 300 sat output as that is below the dust limit
- This is not as expected
- If the P2A output has a value of 200:
- BDK won't use any extra UTXOs and will error because the remaining value is 0 and it enforces the use of at least 1 TxOut even when draining
- This is not as expected

**Expected behavior**
The documentation for `fee_absolute` states the following:
> Note that this is really a minimum absolute fee -- it's possible to overshoot it slightly since adding a change output to drain the remaining excess might not be viable.

Under that assumption I would expect that when spending a P2A output which results in zero or dust change, the entire P2A value should be consumed and no output should be created. If BDK mandates there always being at least 1 TxOut, then I would expect the transaction builder to pull in the extra UTXO to drain to a non-dust output.

**Build environment**
- BDK tag/commit: 2.3.0
- OS+version: macOS 26.2
- Rust/Cargo version: 1.90
- Rust/Cargo target: aarch64-apple-darwin

**Which backend(s) are relevant (if any)?**
- [x] Esplora
- [x] Bitcoin Core RPC

**Is this blocking production use?**
- [x] No: We work around it by trying to detect this problem and increase the fee amount to force 1 sat to be used from another UTXO

**Project or organization (optional)**
[Bark](https://gitlab.com/ark-bitcoin/bark)

**Additional context**
[This is the source code](https://gitlab.com/ark-bitcoin/bark/-/blob/master/bitcoin-ext/src/bdk.rs?ref_type=heads#L157) for where we encounter this issue.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.