diff --git a/src/ui/windows/transactions_tab.cpp b/src/ui/windows/transactions_tab.cpp index d0e5368..0f73805 100644 --- a/src/ui/windows/transactions_tab.cpp +++ b/src/ui/windows/transactions_tab.cpp @@ -425,7 +425,12 @@ void RenderTransactionsTab(App* app) dtx.is_shield = true; dtx.amount = rtx.amount; // positive receive amount dtx.timestamp = std::max(stx.timestamp, rtx.timestamp); - dtx.confirmations = std::min(stx.confirmations, rtx.confirmations); + // Both legs are the SAME transaction, so they share one real confirmation + // count — but the send leg (from z_viewtransaction) often comes through + // with confirmations=0. min() would then make a long-confirmed shield look + // pending (conf==0), which the sort floats to the very top, out of date + // order. Take the populated value. + dtx.confirmations = std::max(stx.confirmations, rtx.confirmations); dtx.address = rtx.address; // shielded destination dtx.from_address = stx.address.empty() ? stx.from_address : stx.address; dtx.memo = rtx.memo.empty() ? stx.memo : rtx.memo; @@ -456,13 +461,16 @@ void RenderTransactionsTab(App* app) } } - // Sort: pending (0-conf) transactions first, then by timestamp descending + // Sort: pending (0-conf) transactions first, then newest-first by timestamp, with txid as + // a final deterministic tiebreak so same-block transactions keep a stable order across + // rebuilds (otherwise equal timestamps reorder every time a new block bumps confirmations). std::sort(display_txns.begin(), display_txns.end(), [](const DisplayTx& a, const DisplayTx& b) { bool aPending = (a.confirmations == 0); bool bPending = (b.confirmations == 0); if (aPending != bPending) return aPending; - return a.timestamp > b.timestamp; + if (a.timestamp != b.timestamp) return a.timestamp > b.timestamp; + return a.txid > b.txid; }); s_display_cache_key = displayKey;