@@ -3541,7 +3541,7 @@ bool CWallet::CreateTransactionInternal(
35413541 CAmount nValue = 0 ;
35423542 ReserveDestination reservedest (this );
35433543 int nChangePosRequest = nChangePosInOut;
3544- const bool sort_bip69{false };
3544+ const bool sort_bip69{nChangePosRequest == - 1 };
35453545 unsigned int nSubtractFeeFromAmount = 0 ;
35463546 for (const auto & recipient : vecSend)
35473547 {
@@ -3722,8 +3722,17 @@ bool CWallet::CreateTransactionInternal(
37223722 assert (nChangePosInOut != -1 );
37233723 auto change_position = txNew.vout .insert (txNew.vout .begin () + nChangePosInOut, newTxOut);
37243724
3725+ // We're making a copy of vecSend because it's const, sortedVecSend should be used
3726+ // in place of vecSend in all subsequent usage.
3727+ std::vector<CRecipient> sortedVecSend{vecSend};
37253728 if (sort_bip69) {
37263729 std::sort (txNew.vout .begin (), txNew.vout .end (), CompareOutputBIP69 ());
3730+ // The output reduction loop uses vecSend to map to txNew.vout, we need to
3731+ // shuffle them both to ensure this mapping remains consistent
3732+ std::sort (sortedVecSend.begin (), sortedVecSend.end (),
3733+ [](const CRecipient& a, const CRecipient& b) {
3734+ return a.nAmount < b.nAmount || (a.nAmount == b.nAmount && a.scriptPubKey < b.scriptPubKey );
3735+ });
37273736
37283737 // If there was a change output added before, we must update its position now
37293738 if (const auto it = std::find (txNew.vout .begin (), txNew.vout .end (), newTxOut); it != txNew.vout .end ()) {
@@ -3783,7 +3792,7 @@ bool CWallet::CreateTransactionInternal(
37833792 CAmount to_reduce = fee_needed + change_amount - change_and_fee;
37843793 int i = 0 ;
37853794 bool fFirst = true ;
3786- for (const auto & recipient : vecSend )
3795+ for (const auto & recipient : sortedVecSend )
37873796 {
37883797 if (i == nChangePosInOut) {
37893798 ++i;
0 commit comments