Skip to content

Add experimental silent payment transaction creation support#220

Open
nymius wants to merge 1 commit intobitcoindevkit:masterfrom
nymius:feat/sp-psbt-send
Open

Add experimental silent payment transaction creation support#220
nymius wants to merge 1 commit intobitcoindevkit:masterfrom
nymius:feat/sp-psbt-send

Conversation

@nymius
Copy link
Contributor

@nymius nymius commented Sep 10, 2025

Description

This PR adds experimental support for creating silent payment transactions through a new CreateSpTx command. The implementation integrates the bdk_sp crate to enable sending Bitcoin to silent payment addresses.

Key changes:

  • Adds bdk_sp dependency as an optional feature
  • Implements CreateSpTx command with support for silent payment recipients
  • Includes parser for silent payment address:amount pairs
  • Returns signed transactions ready for broadcast (not PSBTs due to silent payment derivation constraints)

Notes to the reviewers

  • This feature is marked as EXPERIMENTAL and includes warnings against mainnet use
  • The command returns signed transactions directly rather than PSBTs because silent payment script pubkey derivation cannot be performed securely in a trustless manner with standard PSBT workflows
  • RBF is disabled for silent payment transactions (sequence set to MAX)
  • The implementation handles both single key and extended key signers
  • Error handling uses temporary .expect() calls that should be addressed in future iterations

Changelog notice

Added: Experimental silent payment transaction creation via CreateSpTx command (feature-gated behind sp flag)

Checklists

All Submissions

New Features

* [ ] I've added tests for the new feature

  • I've added docs for the new feature

@nymius nymius requested review from notmandatory and tvpeter and removed request for notmandatory September 10, 2025 19:39
Copy link
Collaborator

@tvpeter tvpeter left a comment

Choose a reason for hiding this comment

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

Thank you for working on adding this feature @nymius,

I couldn't test because I don't know how to construct sp recipients. I will check the documentation on the library and will come back to test it. In the meantime, I have left some comments.
Thank you

@nymius nymius force-pushed the feat/sp-psbt-send branch from bc40b76 to 8d15df7 Compare November 4, 2025 14:12
@nymius nymius requested a review from tvpeter November 4, 2025 14:12
Copy link
Collaborator

@tvpeter tvpeter left a comment

Choose a reason for hiding this comment

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

Thank you for working on this feature @nymius

I left a few comments.

Pls remember to rebase too.

src/handlers.rs Outdated
Comment on lines +366 to +368
if send_all {
tx_builder.drain_wallet().drain_to(recipients[0].0.clone());
} else {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is it possible to drain to an SP address? if so, it will be great to cover that as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, there are different cases for this though:

  1. CreateSpTx receives only a SilentPaymentCode to drain funds.
  2. CreateSpTx is called with the --send_all flag and multiple SilentPaymentCode or other addresses to drain funds.
  3. CreateSpTx is called with the --send_all flag, no SilentPaymentCode, and a plain address.

I've implemented this contemplating 1 and 3 as successful cases, and any variant of 2 as an error.

Comment on lines +467 to +470
for psbt_input in psbt.inputs.iter_mut() {
psbt_input.final_script_sig = None;
psbt_input.final_script_witness = None;
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Won't it be ideal to check if they were actually finalized before resetting?

Copy link
Contributor Author

@nymius nymius Mar 18, 2026

Choose a reason for hiding this comment

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

It shouldn't be necessary, as we are not passing a PSBT around, and the wallet always has all the keys required to sign, but is not difficult to implement. Above, Wallet::sign returns a boolean that indicates if the transaction was finalized or not, so I can check that.

@tvpeter tvpeter moved this to In Progress in BDK-CLI Feb 23, 2026
Copy link

@sdmg15 sdmg15 left a comment

Choose a reason for hiding this comment

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

tested ACK.

Script to use to reproduce

export NETWORK=regtest
export EXT_DESCRIPTOR='wpkh(tprv8ZgxMBicQKsPdMzWj9KHvoExKJDqfZFuT5D8o9XVZ3wfyUcnPNPJKncq5df8kpDWnMxoKbGrpS44VawHG17ZSwTkdhEtVRzSYXd14vDYXKw/0/*)'
export INT_DESCRIPTOR='wpkh(tprv8ZgxMBicQKsPdMzWj9KHvoExKJDqfZFuT5D8o9XVZ3wfyUcnPNPJKncq5df8kpDWnMxoKbGrpS44VawHG17ZSwTkdhEtVRzSYXd14vDYXKw/1/*)'
export DATABASE_TYPE="sqlite"
export CLIENT_TYPE="rpc"
export SERVER_URL="http://127.0.0.1:18443"
export COOKIE="/home/user/.bitcoin/regtest/.cookie"
export SP_RECIPIENT="sprt1qqdu4udd7wz7flf89m27teqzp8gxzvgpg3xudw89c0ce0f0pe0gwz6qkc4d7dg587w9rkaa0cj8rf3c28z0g45tgn0t7fzkk4s867w3eugga03ret"

raw_tx=$(cargo run -- wallet create_sp_tx --to-sp $SP_RECIPIENT:1000 | jq -r '.raw_tx' | tr -d '\n')
cargo run --features rpc -- wallet broadcast --tx $raw_tx
Image

let _resigned = wallet.sign(&mut psbt, SignOptions::default())?;

let raw_tx = psbt.extract_tx()?;
if cli_opts.pretty {
Copy link

Choose a reason for hiding this comment

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

Here to actually make this "pretty", there's is this shorten function that can be used. I'm not though convinced if that's helpful for users wanting to copy the full raw tx maybe they should just not use the pretty format.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point, I'm not sure about the use cases of the pretty flag, but I'm against shortening the transaction.

@nymius nymius force-pushed the feat/sp-psbt-send branch from 8d15df7 to 8290461 Compare March 18, 2026 19:22
@nymius
Copy link
Contributor Author

nymius commented Mar 18, 2026

I've addressed the pending comments:

  • Checked the finalization status of the PSBT after the signing phase before silent payment output derivation.
  • Implemented logic to handle the drain to silent payment case.

I've also:

  • Changed the feature flag sp to silent-payments for more clarity.
  • Squashed all commits into a single one.

@codecov
Copy link

codecov bot commented Mar 18, 2026

Codecov Report

❌ Patch coverage is 0% with 187 lines in your changes missing coverage. Please review.
✅ Project coverage is 10.39%. Comparing base (af0d98e) to head (beaca7e).
⚠️ Report is 9 commits behind head on master.

Files with missing lines Patch % Lines
src/handlers.rs 0.00% 171 Missing ⚠️
src/utils.rs 0.00% 16 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #220      +/-   ##
==========================================
- Coverage   11.16%   10.39%   -0.77%     
==========================================
  Files           8        8              
  Lines        2482     2665     +183     
==========================================
  Hits          277      277              
- Misses       2205     2388     +183     
Flag Coverage Δ
rust 10.39% <0.00%> (-0.77%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@nymius nymius force-pushed the feat/sp-psbt-send branch from 8290461 to d297c8e Compare March 19, 2026 22:15
- Adds CreateSpTx command to create transactions with silent payment
  outputs: this command creates signed transactions directly rather than
  PSBTs due to current limitations in secure shared derivation.

  It supports mixed recipients: regular addresses + silent payments.
  It DOES NOT support RBF for the created transactions.
  It generates signed transactions ready for broadcasting.

- Adds SilentPaymentCode command to create silent payment codes from
  public keys and network: the silent payment code generated is
  independent from any of the other stateful features of bdk-cli.

  This command is mainly intended for experimental use, do not lock any
  funds to the generated code if you don't know what you are doing and
  don't have the keys matching the public keys used.

- Adds bdk_sp dependency with "silent-payments" feature flag.
- Adds silent payment recipient parsing utility.
- Add README section for new silent payment commands.

Note: This is experimental functionality for testing only, not
recommended for mainnet use.
@nymius nymius force-pushed the feat/sp-psbt-send branch from d297c8e to beaca7e Compare March 19, 2026 22:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

3 participants