Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 57 additions & 20 deletions lib/db/isar/main_db.dart
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,9 @@ class MainDB {

await isar.writeTxn(() async {
final set = utxos.toSet();
final noteValues = <String, String?>{};
for (final utxo in utxos) {
UTXO persistedUtxo = utxo;
// check if utxo exists in db and update accordingly
final storedUtxo = await isar.utxos
.where()
Expand All @@ -342,24 +344,36 @@ class MainDB {
!storedUtxo.isBlocked &&
!storedUtxo.userUnfroze;
set.remove(utxo);
set.add(
storedUtxo.copyWith(
value: utxo.value,
address: utxo.address,
blockTime: utxo.blockTime,
blockHeight: utxo.blockHeight,
blockHash: utxo.blockHash,
// passing null keeps the stored value
isBlocked: applyAutoBlock ? true : null,
blockedReason: applyAutoBlock ? utxo.blockedReason : null,
name: applyAutoBlock && storedUtxo.name.isEmpty
? utxo.name
: null,
),
persistedUtxo = storedUtxo.copyWith(
value: utxo.value,
address: utxo.address,
blockTime: utxo.blockTime,
blockHeight: utxo.blockHeight,
blockHash: utxo.blockHash,
// passing null keeps the stored value
isBlocked: applyAutoBlock ? true : null,
blockedReason: applyAutoBlock ? utxo.blockedReason : null,
name: applyAutoBlock && storedUtxo.name.isEmpty ? utxo.name : null,
);
set.add(persistedUtxo);
} else {
newUTXO = true;
}

if (persistedUtxo.name.isEmpty) {
final noteValue = noteValues.containsKey(utxo.txid)
? noteValues[utxo.txid]
: (await isar.transactionNotes.getByTxidWalletId(
utxo.txid,
walletId,
))?.value;
noteValues[utxo.txid] = noteValue;
if (noteValue?.isNotEmpty == true) {
set
..remove(persistedUtxo)
..add(persistedUtxo.copyWith(name: noteValue));
}
}
}

await isar.utxos.where().walletIdEqualTo(walletId).deleteAll();
Expand All @@ -381,14 +395,37 @@ class MainDB {
isar.transactionNotes.where().walletIdEqualTo(walletId);

Future<void> putTransactionNote(TransactionNote transactionNote) =>
isar.writeTxn(() async {
await isar.transactionNotes.put(transactionNote);
});
putTransactionNotes([transactionNote]);

/// Copies a note only to blank UTXO labels. The label is independent after
/// that first assignment, so later note edits cannot overwrite it.
Future<void> putTransactionNotes(List<TransactionNote> transactionNotes) =>
isar.writeTxn(() async {
await isar.transactionNotes.putAll(transactionNotes);
});
transactionNotes.isEmpty
? Future.value()
: isar.writeTxn(() async {
await isar.transactionNotes.putAll(transactionNotes);

final toUpdate = <UTXO>[];
for (final note in transactionNotes) {
if (note.value.isEmpty) {
continue;
}
final utxos = await isar.utxos
.where()
.walletIdEqualTo(note.walletId)
.filter()
.txidEqualTo(note.txid)
.findAll();
toUpdate.addAll(
utxos
.where((utxo) => utxo.name.isEmpty)
.map((utxo) => utxo.copyWith(name: note.value)),
);
}
if (toUpdate.isNotEmpty) {
await isar.utxos.putAll(toUpdate);
}
});

Future<TransactionNote?> getTransactionNote(
String walletId,
Expand Down
10 changes: 5 additions & 5 deletions lib/pages/cakepay/cakepay_confirm_send_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import '../../notifications/show_flush_bar.dart';
import '../../pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_auth_send.dart';
import '../../providers/providers.dart';
import '../../route_generator.dart';
import '../../services/transaction_note_service.dart';
import '../../themes/stack_colors.dart';
import '../../utilities/amount/amount_formatter.dart';
import '../../utilities/constants.dart';
Expand Down Expand Up @@ -95,11 +96,10 @@ class _CakePayConfirmSendViewState

txid = (results.first as TxData).txid!;

await ref
.read(mainDBProvider)
.putTransactionNote(
TransactionNote(walletId: walletId, txid: txid, value: note),
);
await saveTransactionNotesAfterSend(
notes: [TransactionNote(walletId: walletId, txid: txid, value: note)],
persist: ref.read(mainDBProvider).putTransactionNotes,
);

if (context.mounted) {
// pop sending dialog (pushed via showDialog which uses root navigator)
Expand Down
11 changes: 5 additions & 6 deletions lib/pages/exchange_view/confirm_change_now_send.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import '../../notifications/show_flush_bar.dart';
import '../../pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_auth_send.dart';
import '../../providers/providers.dart';
import '../../route_generator.dart';
import '../../services/transaction_note_service.dart';
import '../../themes/stack_colors.dart';
import '../../utilities/amount/amount.dart';
import '../../utilities/amount/amount_formatter.dart';
Expand Down Expand Up @@ -135,12 +136,10 @@ class _ConfirmChangeNowSendViewState

txid = (results.first as TxData).txid!;

// save note
await ref
.read(mainDBProvider)
.putTransactionNote(
TransactionNote(walletId: walletId, txid: txid, value: note),
);
await saveTransactionNotesAfterSend(
notes: [TransactionNote(walletId: walletId, txid: txid, value: note)],
persist: ref.read(mainDBProvider).putTransactionNotes,
);

await ref
.read(tradeSentFromStackLookupProvider)
Expand Down
21 changes: 13 additions & 8 deletions lib/pages/namecoin_names/confirm_name_transaction_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import '../../pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/deskt
import '../../providers/global/secure_store_provider.dart';
import '../../providers/providers.dart';
import '../../route_generator.dart';
import '../../services/transaction_note_service.dart';
import '../../themes/stack_colors.dart';
import '../../themes/theme_providers.dart';
import '../../utilities/amount/amount.dart';
Expand Down Expand Up @@ -140,14 +141,18 @@ class _ConfirmNameTransactionViewState
ref.refresh(desktopUseUTXOs);
}

// save note
for (final txid in txids) {
await ref
.read(mainDBProvider)
.putTransactionNote(
TransactionNote(walletId: walletId, txid: txid, value: note),
);
}
await saveTransactionNotesAfterSend(
notes: txids
.map(
(txid) => TransactionNote(
walletId: walletId,
txid: txid,
value: note,
),
)
.toList(),
persist: ref.read(mainDBProvider).putTransactionNotes,
);

unawaited(wallet.refresh());

Expand Down
18 changes: 10 additions & 8 deletions lib/pages/send_view/confirm_transaction_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import '../../pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/deskt
import '../../providers/providers.dart';
import '../../providers/wallet/public_private_balance_state_provider.dart';
import '../../route_generator.dart';
import '../../services/transaction_note_service.dart';
import '../../themes/stack_colors.dart';
import '../../themes/theme_providers.dart';
import '../../utilities/amount/amount.dart';
Expand Down Expand Up @@ -458,14 +459,15 @@ class _ConfirmTransactionViewState
ref.refresh(desktopUseUTXOs);
}

// save note
for (final txid in txids) {
await ref
.read(mainDBProvider)
.putTransactionNote(
TransactionNote(walletId: walletId, txid: txid, value: note),
);
}
await saveTransactionNotesAfterSend(
notes: txids
.map(
(txid) =>
TransactionNote(walletId: walletId, txid: txid, value: note),
)
.toList(),
persist: ref.read(mainDBProvider).putTransactionNotes,
);

if (widget.isTokenTx) {
if (wallet is SolanaWallet) {
Expand Down
15 changes: 6 additions & 9 deletions lib/pages/shopinbit/shopinbit_confirm_send_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import '../../pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/deskt
import '../../providers/global/shopin_bit_service_provider.dart';
import '../../providers/providers.dart';
import '../../route_generator.dart';
import '../../services/transaction_note_service.dart';
import '../../themes/stack_colors.dart';
import '../../utilities/amount/amount.dart';
import '../../utilities/amount/amount_formatter.dart';
Expand Down Expand Up @@ -113,12 +114,10 @@ class _ShopInBitConfirmSendViewState

txid = (results.first as TxData).txid!;

// save note
await ref
.read(mainDBProvider)
.putTransactionNote(
TransactionNote(walletId: walletId, txid: txid, value: note),
);
await saveTransactionNotesAfterSend(
notes: [TransactionNote(walletId: walletId, txid: txid, value: note)],
persist: ref.read(mainDBProvider).putTransactionNotes,
);

// The server (and the BTCPay webhook) own ticket + payment state from
// here, so there's nothing to persist locally; just nudge a refresh so
Expand All @@ -132,9 +131,7 @@ class _ShopInBitConfirmSendViewState
final popThroughRouteName = widget.popThroughRouteName;
if (popThroughRouteName != null) {
final navigator = Navigator.of(context, rootNavigator: true);
navigator.popUntil(
ModalRoute.withName(popThroughRouteName),
);
navigator.popUntil(ModalRoute.withName(popThroughRouteName));
navigator.pop();
} else {
// pop sending dialog (pushed via showDialog which uses root navigator)
Expand Down
18 changes: 10 additions & 8 deletions lib/pages/spark_names/confirm_spark_name_transaction_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import '../../pages_desktop_specific/coin_control/desktop_coin_control_use_dialo
import '../../pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_auth_send.dart';
import '../../providers/providers.dart';
import '../../route_generator.dart';
import '../../services/transaction_note_service.dart';
import '../../themes/stack_colors.dart';
import '../../themes/theme_providers.dart';
import '../../utilities/amount/amount.dart';
Expand Down Expand Up @@ -119,14 +120,15 @@ class _ConfirmSparkNameTransactionViewState
txids.addAll(txData.sparkSpends?.map((e) => e.txid!) ?? [txData.txid!]);
ref.refresh(desktopUseUTXOs);

// save note
for (final txid in txids) {
await ref
.read(mainDBProvider)
.putTransactionNote(
TransactionNote(walletId: walletId, txid: txid, value: note),
);
}
await saveTransactionNotesAfterSend(
notes: txids
.map(
(txid) =>
TransactionNote(walletId: walletId, txid: txid, value: note),
)
.toList(),
persist: ref.read(mainDBProvider).putTransactionNotes,
);

final address = txData.sparkNameInfo?.sparkAddress;
final currentReceiving = await wallet.getCurrentReceivingSparkAddress();
Expand Down
27 changes: 27 additions & 0 deletions lib/services/transaction_note_service.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* This file is part of Stack Wallet.
*
* Copyright (c) 2023 Cypher Stack
* All Rights Reserved.
* The code is distributed under GPLv3 license, see LICENSE file for details.
*/

import '../models/isar/models/transaction_note.dart';
import '../utilities/logger.dart';

Future<bool> saveTransactionNotesAfterSend({
required List<TransactionNote> notes,
required Future<void> Function(List<TransactionNote>) persist,
}) async {
try {
await persist(notes);
return true;
} catch (e, s) {
Logging.instance.w(
"Transaction sent, but its note could not be saved",
error: e,
stackTrace: s,
);
return false;
}
}
Loading
Loading