What changed, and why it matters
This commit fixes two user-interface bugs in the new transaction-details screen. First, notes attached to Mimblewimble/EPIC transactions were being saved under the wrong ID, so the note could be lost or mismatched. Second, trade cards were incorrectly shown for every outgoing transaction, even when no real trade existed, causing confusing or duplicate UI elements. These are correctness/UX fixes, not remote-exploitable security vulnerabilities.
Treat as a routine bug-fix release; no urgent security response required. Verify that notes for existing Mimblewimble/EPIC transactions migrate or remain visible after the ID change.
Security signals we found
Data-integrity issue: transaction note keyed by wrong identifier could lead to note loss or mis-association
UI-only fix with no input validation, parsing, or privilege changes
No secrets, credentials, or sensitive data handling modified
Evidence from the diff
The patch changes how the v2 transaction details view selects the transaction identifier used for editable notes and note lookups. Previously it used _transaction.txid or a coin-type conditional that forced slateId.toString(); now it consistently uses _transaction.slateId ?? _transaction.txid. In the list item, it restricts trade-card matching to outgoing transactions with a non-empty txid, preventing empty/irrelevant trade-card rendering. No cryptographic, networking, or permission code is touched.
Changed components
lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_details_view.dartlib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_list_item.dartInspect captured patch +24 / −23
diff --git a/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_details_view.dart b/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_details_view.dart
index 521ed9f..2b310bb 100644
--- a/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_details_view.dart
+++ b/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_details_view.dart
@@ -1019,6 +1019,8 @@ class _TransactionV2DetailsViewState
maxHeight: 360,
child: EditNoteView(
txid:
+ _transaction
+ .slateId ??
_transaction.txid,
walletId: walletId,
),
@@ -1034,7 +1036,8 @@ class _TransactionV2DetailsViewState
).pushNamed(
EditNoteView.routeName,
arguments: Tuple2(
- _transaction.txid,
+ _transaction.slateId ??
+ _transaction.txid,
walletId,
),
);
@@ -1069,12 +1072,8 @@ class _TransactionV2DetailsViewState
.watch(
pTransactionNote((
txid:
- (coin is Epiccash ||
- coin
- is Mimblewimblecoin)
- ? _transaction.slateId
- .toString()
- : _transaction.txid,
+ _transaction.slateId ??
+ _transaction.txid,
walletId: walletId,
)),
)
diff --git a/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_list_item.dart b/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_list_item.dart
index 0ae6414..a9d0dee 100644
--- a/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_list_item.dart
+++ b/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_list_item.dart
@@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:tuple/tuple.dart';
+import '../../../../models/exchange/response_objects/trade.dart';
import '../../../../models/isar/models/blockchain_data/v2/transaction_v2.dart';
import '../../../../models/isar/models/isar_models.dart';
import '../../../../providers/global/trades_service_provider.dart';
@@ -38,12 +39,17 @@ class TxListItem extends ConsumerWidget {
if (tx is TransactionV2) {
final _tx = tx as TransactionV2;
- final matchingTrades = ref
- .read(tradesServiceProvider)
- .trades
- .where((e) => e.payInTxid == _tx.txid || e.payOutTxid == _tx.txid);
+ final Iterable<Trade> matchingTrades =
+ _tx.type == TransactionType.outgoing && _tx.txid.isNotEmpty
+ ? ref
+ .read(tradesServiceProvider)
+ .trades
+ .where(
+ (e) => e.payInTxid == _tx.txid || e.payOutTxid == _tx.txid,
+ )
+ : [];
- if (_tx.type == TransactionType.outgoing && matchingTrades.isNotEmpty) {
+ if (matchingTrades.isNotEmpty) {
final trade = matchingTrades.first;
return Container(
decoration: BoxDecoration(
@@ -54,10 +60,7 @@ class TxListItem extends ConsumerWidget {
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
- TransactionCardV2(
- key: UniqueKey(),
- transaction: _tx,
- ),
+ TransactionCardV2(key: UniqueKey(), transaction: _tx),
TradeCard(
key: Key(
_tx.txid +
@@ -94,7 +97,8 @@ class TxListItem extends ConsumerWidget {
Text(
"Trade details",
style: STextStyles.desktopH3(
- context),
+ context,
+ ),
),
DesktopDialogCloseButton(
onPressedOverride: Navigator.of(
@@ -111,8 +115,9 @@ class TxListItem extends ConsumerWidget {
// TODO: [prio:med]
// transactionIfSentFromStack: tx,
transactionIfSentFromStack: null,
- walletName: ref
- .watch(pWalletName(_tx.walletId)),
+ walletName: ref.watch(
+ pWalletName(_tx.walletId),
+ ),
walletId: _tx.walletId,
),
),
@@ -171,10 +176,7 @@ class TxListItem extends ConsumerWidget {
borderRadius: radius,
),
child: Breathing(
- child: FusionTxGroupCard(
- key: UniqueKey(),
- group: group,
- ),
+ child: FusionTxGroupCard(key: UniqueKey(), group: group),
),
);
}
Why this scored 16/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.