Update RBF nsequence to 0xFFFFFFFD (#3077)
What changed, and why it matters
Cake Wallet was setting a Bitcoin transaction value (called nSequence) to 1 when enabling Replace-By-Fee (RBF). The value 1 does technically opt into RBF, but it also tells the network the transaction cannot be mined until 1 block has passed, which is a relative timelock. This is likely unintended, makes Cake Wallet transactions stand out as unusual, and can cause problems in collaborative transactions like PayJoin. The fix changes the value to 0xFFFFFFFD, the standard value wallets use for RBF.
Review whether any in-flight or historical transactions used nSequence=0x1 and assess if the unintended 1-block relative timelock caused stuck transactions or fingerprinting exposure. Consider adding a test to assert nSequence values for RBF and non-RBF paths.
Security signals we found
Unintended relative timelock on RBF transactions
Wallet fingerprinting via non-standard nSequence value
Potential breakage or privacy degradation in collaborative transactions (e.g., PayJoin)
Fix aligns with standard wallet behavior
Evidence from the diff
The patch changes the nSequence value used for RBF opt-in from 0x1 to 0xFFFFFFFD. Per BIP-68/125, nSequence ≤ 0xFFFFFFFE signals RBF, but values below 0xFFFFFFFD also encode a relative timelock (0x1 = 1-block relative timelock). Using 0x1 therefore imposes an unintended 1-block relative locktime while still enabling RBF. It also creates a wallet fingerprint because 0x1 is non-standard. 0xFFFFFFFD is the conventional value for pure RBF opt-in without a relative timelock. The non-RBF branch remains 0xffffffff (final).
Changed components
cw_bitcoin/lib/psbt/transaction_builder.dartInspect captured patch +1 / −1
diff --git a/cw_bitcoin/lib/psbt/transaction_builder.dart b/cw_bitcoin/lib/psbt/transaction_builder.dart
index 7d2baded..2046e45c 100644
--- a/cw_bitcoin/lib/psbt/transaction_builder.dart
+++ b/cw_bitcoin/lib/psbt/transaction_builder.dart
@@ -25,7 +25,7 @@ class PSBTTransactionBuild {
psbt.setInputPreviousTxId(i, Uint8List.fromList(hex.decode(input.utxo.txHash).reversed.toList()));
psbt.setInputOutputIndex(i, input.utxo.vout);
- psbt.setInputSequence(i, enableRBF ? 0x1 : 0xffffffff);
+ psbt.setInputSequence(i, enableRBF ? 0xfffffffd : 0xffffffff);
if (input.utxo.isSegwit()) {
Why this scored 48/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.