Skip to content

Conversation

@kumulynja
Copy link
Contributor

@kumulynja kumulynja commented Dec 30, 2025

Description

This PR adds the only_witness_utxo and add_foreign_utxo on TxBuilder since they are available in bdk, but missing in bdk-ffi. They are useful for bdk bindings to be used together with for example bark (Ark implementation from Second Tech) so a unilateral exit can be done with Cpfp transactions.

Notes to the reviewers

Since the add_foreign_utxo function is still experimental, I added the same comments mentioning this and the caution that has to be taken. I think it is good to expose it already though for experimentation like with bark as mentioned before.

Both functions seem to be working in an example in Dart to unilaterally exit from bark through a fork of both bdk-ffi and bdk-dart.

Documentation

  • bdk-ffi

Checklists

All Submissions:

  • I've signed all my commits
  • I followed the contribution guidelines
  • I ran cargo fmt and cargo clippy before committing
  • I've added a changelog in the next release tracking issue (see example)

New Features:

  • I've added tests for the new feature
  • I've added docs for the new feature

@reez
Copy link
Collaborator

reez commented Jan 6, 2026

linking some related issues looking for this functionality:

#329

#926

Copy link
Collaborator

@reez reez left a comment

Choose a reason for hiding this comment

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

Thanks for adding, this is looking like the right shape to me, I left a couple comments to address, otherwise this is looking good

psbt_input: Input,
satisfaction_weight: u64,
) -> Result<Arc<Self>, AddForeignUtxoError> {
let bdk_outpoint: BdkOutPoint = outpoint.into();
Copy link
Collaborator

Choose a reason for hiding this comment

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

should we guard here if psbt_input lacks both witness_utxo and non_witness_utxo

if psbt_input.witness_utxo.is_none() && psbt_input.non_witness_utxo.is_none() {
  return Err(AddForeignUtxoError::MissingUtxo);
}

would match upstream behavior at the method boundary instead of deferring failure to finish()

https://docs.rs/bdk_wallet/latest/bdk_wallet/tx_builder/struct.TxBuilder.html#method.add_foreign_utxo

"This method returns errors… The psbt_input does not contain a witness_utxo or non_witness_utxo."

})
}

/// Add a foreign UTXO i.e. a UTXO not owned by this wallet.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Docs here don’t look identical to upstream add_foreign_utxo any reason for that?

})
}

/// Only fill witness_utxo.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Docs here don’t look identical to upstream only_witness_utxo any reason for that?

}

#[test]
fn test_add_foreign_utxo_missing_witness_data() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

if we add the guard in add_foreign_utxo (per my code comment in tx_builder.rs) we should update the test for that too

Copy link
Member

@thunderbiscuit thunderbiscuit left a comment

Choose a reason for hiding this comment

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

A few questions I'd like to clear up before moving forward. I also agree with @reez comments about matching docs!

I'm also wondering if the only_witness_utxo API is tied to the add_foreign_utxo in your use case in some way or if you just added it because it wasn't there and you saw it as an easy win (I don't mind adding it, I just want to make sure I understand the use for it).

Thanks for the hard work! I know it's a big one.

Note: it also needs a rebase.

Comment on lines +380 to +381
/// This is automatically set when working with SegWit transactions. The `witness_utxo` field
/// is enough to construct the signature hash.
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure how true this statement is, or at least it's not in the original docs, and your default value on the field is false. I'd remove this line for now. Was there a reason you added it?

}
}

impl TryFrom<Input> for BdkInput {
Copy link
Member

Choose a reason for hiding this comment

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

I don't know if implementing the TryFrom trait here is required since we already have the From trait implemented. Is there a reason to use the psbt_input.try_into()?; instead of just .into() and returning the error on the TxBuilder if the conversion fails?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

3 participants