Skip to content

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

@PeteClubSeven

Description

@PeteClubSeven

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)?

  • Esplora
  • Bitcoin Core RPC

Is this blocking production use?

  • 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

Additional context
This is the source code for where we encounter this issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    Status

    Todo

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions