fix: avoid UIH2 fingerprint in payjoin receiver input selection (#3304)

Co-authored-by: Konstantin Ullrich <konstantin@cakewallet.com>

Cindy committed Jun 18, 2026 at 05:45 UTC 874d724c67ce7d804524e1f2a31f445998e5392a
1 file changed +11 -1
cw_bitcoin/lib/payjoin/payjoin_receive_worker.dart
+11 -1
@@ -179,7 +179,17 @@ class PayjoinReceiverWorker {
179 final unspent = listUnspent as List<UtxoWithPrivateKey>;
180 if (unspent.isEmpty) throw RecoverableError('No unspent outputs available');
181
182 - final selectedUtxo = await _inputPairFromUtxo(unspent[0]);
182 + final candidateInputs =
183 + await Future.wait(unspent.map(_inputPairFromUtxo));
184 +
185 + // Prefer a UTXO that avoids the Unnecessary Input Heuristic (UIH2);
186 + // fall back to the first candidate if none preserves privacy.
187 + InputPair selectedUtxo = candidateInputs.first;
188 + try {
189 + selectedUtxo =
190 + await pj5.tryPreservingPrivacy(candidateInputs: candidateInputs);
191 + } catch (_) {}
192 +
193 final pj6 = await pj5.contributeInputs(replacementInputs: [selectedUtxo]);
194 final pj7 = await pj6.commitInputs();
195