Skip to content

Balance categorization: wallet-generated transactions to external addresses incorrectly marked as untrusted_pending #273

@schjonhaug

Description

@schjonhaug

Describe the bug
BDK incorrectly categorizes unconfirmed UTXOs sent to external/receive addresses as
untrusted_pending even when the transaction is generated by the wallet itself (spending wallet's own
UTXOs to wallet's own addresses). According to BDK documentation, trusted_pending should include
"Unconfirmed UTXOs generated by a wallet tx", but the current implementation only considers outputs to
internal/change addresses as trusted, regardless of transaction origin.

To Reproduce

  1. Create a wallet with both external (receive) and internal (change) addresses
  2. Fund the wallet with confirmed UTXOs
  3. Create a consolidation transaction that spends wallet UTXOs to a wallet-owned external address
    (using raw transaction APIs like Bitcoin Core's createrawtransaction)
  4. Sync the wallet and check balance categorization
  5. Repeat the same consolidation but sending to an internal/change address

Expected behavior
Both consolidation transactions should result in trusted_pending UTXOs since they are generated by
the wallet (spending wallet's own UTXOs to wallet's own addresses). The destination keychain (external
vs internal) should not affect trust classification when the wallet created the transaction.

Actual behavior:

Case 1: Consolidation to External/Receive Address
🔄 Consolidating 2 UTXOs ...
💰 Total: 0.02000000 BTC → 0.01990000 BTC (0.0001 BTC fee)
🎯 Consolidating to: bcrt1qghklxanlt9wnjxuqdgfuzcg66n28rw0m3wqjl4

Address generated with: bitcoin-cli getnewaddress (external keychain)
Address appears in BDK logs as: External 33: bcrt1qghklxanlt9wnjxuqdgfuzcg66n28rw0m3wqjl4

BDK Balance Result:

Wallet Before After Diff
Trusted pending
Unconfirmed pending 0.01990000 BTC +0.01990000 BTC ❌
Confirmed 0.99970000 BTC 0.97970000 BTC -0.02000000 BTC
Total 0.99970000 BTC 0.99960000 BTC -0.00010000 BTC

Case 2: Consolidation to Internal/Change Address
🔄 Consolidating UTXOs...
💰 Total: 0.02000000 BTC → 0.01990000 BTC (0.0001 BTC fee)
🎯 Consolidating to: bcrt1q293wv26t0s2242vec2jr5jwx63fezwshu29agy

Address generated with: bitcoin-cli getrawchangeaddress (internal keychain)
Address appears in BDK logs as: Internal 0: bcrt1q293wv26t0s2242vec2jr5jwx63fezwshu29agy

BDK Balance Result:

Wallet Before After Diff
Trusted pending 0.01990000 BTC +0.01990000 BTC ✅
Unconfirmed pending
Confirmed 0.99980000 BTC 0.97980000 BTC -0.02000000 BTC
Total 0.99980000 BTC 0.99970000 BTC -0.00010000 BTC

Build environment

  • BDK tag/commit: bdk_wallet = "2"
  • OS+version: macOS (Darwin 24.5.0)
  • Rust/Cargo version: Latest stable
  • Rust/Cargo target: x86_64-apple-darwin

Additional context
This relates to the existing issue #16 about naive trust classification. The current implementation
determines trust based on the destination keychain (internal vs external) rather than whether the
wallet created the transaction by spending its own UTXOs.

In both test cases above, the wallet is spending its own confirmed UTXOs to create new unconfirmed
UTXOs at wallet-owned addresses. According to the BDK documentation, these should be trusted_pending
since they are "unconfirmed UTXOs generated by a wallet tx." However, BDK only considers them trusted
when sent to internal/change addresses, creating inconsistent behavior where identical
wallet-generated transactions are categorized differently based solely on the destination address
type.

This inconsistency could lead to incorrect balance reporting and potentially unsafe spending decisions
in applications that rely on the trust categorization to determine spendable balances.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions