Skip to content

[privacy] Implement Joinstr coinjoin (proof of concept) - #2441

Draft
kwsantiago wants to merge 49 commits into
SatoshiPortal:developfrom
kwsantiago:joinstr-demo
Draft

[privacy] Implement Joinstr coinjoin (proof of concept)#2441
kwsantiago wants to merge 49 commits into
SatoshiPortal:developfrom
kwsantiago:joinstr-demo

Conversation

@kwsantiago

@kwsantiago kwsantiago commented Jul 12, 2026

Copy link
Copy Markdown

This pull request implements a proof of concept for Joinstr, a coinjoin protocol coordinated over Nostr. Peers combine one input each into a single transaction that pays every peer an equal-denomination output back to their own wallet.

Read more: joinstr.xyz

Uses the joinstr_flutter bindings. Behind superuser settings, testnet only, hot BIP84 wallets only.

TODO:

  • Add screenshots
  • Tests

Comment thread lib/features/joinstr/domain/usecases/list_joinstr_pools_usecase.dart Outdated
Comment thread lib/features/joinstr/joinstr_locator.dart Outdated
Comment thread lib/features/joinstr/ui/screens/joinstr_screen.dart Outdated
Comment thread lib/features/joinstr/domain/usecases/resolve_joinstr_peer_context_usecase.dart Outdated
Comment thread lib/features/joinstr/domain/joinstr.dart
@1440000bytes

Copy link
Copy Markdown

Thanks for implementing joinstr in bull wallet. I have made the UI/UX here consistent with joinstr-kmp and joinstr-floresta in this branch: https://github.com/1440000bytes/bullbitcoin-mobile/tree/joinstr-pr2441

It also includes some tests and bug fixes. You can find the APK for it here: https://github.com/1440000bytes/bullbitcoin-mobile/actions/runs/29418299164

@kwsantiago
kwsantiago requested a review from 1440000bytes July 15, 2026 18:01
@1440000bytes

1440000bytes commented Jul 15, 2026

Copy link
Copy Markdown

Thanks for addressing the previous review comments. I have added tor, fixed UI/UX and moved joinstr to home screen in these commits:

1440000bytes@31de259
1440000bytes@b4ac733
1440000bytes@0b393bf
1440000bytes@2bdab00
1440000bytes@d0955f5

Pull request to add socks5 proxy in rust-joinstr: rust-joinstr/joinstr#36
APK: https://github.com/1440000bytes/bullbitcoin-mobile/actions/runs/29457022360

…limit walk

Signed-off-by: Kyle 🐆 <kyle@privkey.io>
…in error

Signed-off-by: Kyle 🐆 <kyle@privkey.io>
@kwsantiago

kwsantiago commented Jul 16, 2026

Copy link
Copy Markdown
Author

Merged your 5 commits (Tor, UI/UX, home-screen tile, tests) into the branch. Two deltas on top:

  • Kept two earlier bug fixes that weren't on your branch: reserve the output address across retries (avoids walking the gap limit on failed rounds), and surface the scanned range in the no-eligible-coin error.
  • Repinned joinstr_flutter b75eea0 -> d1bb9f8 (rust-joinstr master tip), which adds the Reject SOCKS5 no-auth and keep resumed rounds on Tor rust-joinstr/joinstr#39 hardening: reject SOCKS5 no-auth to preserve circuit isolation, and carry the proxy in resumed State.

analyze clean, joinstr tests green.

Re-pin joinstr_flutter to 4f21626: list_coins now returns the real electrum error when a scan finds nothing, so an unreachable server no longer looks like an empty wallet. The create picker's empty state says no spendable coins were found rather than mentioning a denomination the new flow never asks for.
list_coins now fetches the whole address range in a few batched electrum requests instead of a round trip per address, so the create-pool screen no longer hangs on 'Loading coins...' over tor.
Batch size was above blockstream electrs's limit, so the create-pool scan returned empty even when the wallet held coins. Pins the batch-size fix (a4efdd4).
Timeline drops the transient connecting step and gives every step a description line carrying real data (input outpoint, broadcast txid), mirroring joinstr-kmp and floresta; the first row reads Join Pool for a joiner since posting only happens for the creator. Re-pin joinstr to the gap-limited, retrying scan (1604653) so coins load in seconds over tor. Drop the Tor mention from the pools loading label.
…atus

Re-pin joinstr to the electrum auto-reconnect fix (5fd842c) so a coinjoin no longer fails with WouldBlock or connection-closed when the electrum link goes idle over tor while waiting for peers. My Pools no longer shows Connecting as a pool's first status: the transient connecting step maps to the real first step (Announce Pool, or Join Pool for a joiner).
Registers the input over a fresh tor circuit so the relay cannot link a peer's input to its output.
Re-pin joinstr to 01066eb: the rotation dropped the connection before the output event reached the relay, so the joiner waited forever. Restores the working single-connection flow; circuit isolation returns done the reference way (per-registration circuit + await relay OK).
Re-pin joinstr to 64342ad: each output/input registration now posts over its own tor circuit and waits for the relay OK, so a peer's input is unlinkable from its output and no registration is silently dropped (the joiner deadlock). The timeline now shows real data like the reference wallets: the output address, the relay event ids acknowledging the output and input registrations, the finalized PSBT on the finalize step, and the txid on broadcast.
Isolated sends for output/input registration were failing with 'socks5 connect failed': measured against real tor, building a fresh circuit occasionally took past the old 10s connect budget. Pins the fix (6c284af): wider timeout + retry on a new circuit.
@1440000bytes

1440000bytes commented Jul 21, 2026

Copy link
Copy Markdown

@pievalentin

Copy link
Copy Markdown

Very cool stuff!

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants