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