What changed, and why it matters
This commit makes a small UI safety tweak in the transaction confirmation screen of a cryptocurrency wallet. It moves a database lookup slightly later in the code and ensures a state update happens after the screen has finished its initial build, which helps avoid a rare Flutter framework error. There is no direct evidence this fixes a security vulnerability, but it is a defensive safeguard against possible app crashes or inconsistent UI state when checking whether a transaction would accidentally spend a valuable 'ordinal' asset.
Treat as a routine robustness improvement. Reviewers may optionally verify that `_checkForOrdinalSpend` is not called from other contexts that now require the new parameter, and confirm no regression in ordinal-spend warnings. No urgent security response is indicated by the diff alone.
Security signals we found
Defensive state-management change to avoid calling setState before first frame
Avoids unnecessary database access in non-ordinal/non-UTXO paths
No explicit security claim, CVE, or exploit mechanism described in commit
No changes to cryptography, transaction signing, validation, or network logic
Evidence from the diff
In lib/pages/send_view/confirm_transaction_view.dart, the patch (1) reorders an import, (2) moves the final db = ref.read(mainDBProvider); lookup after the early-return checks, (3) adds an updateStateInPostFrameCallback flag so _checkForOrdinalSpend can schedule setState via WidgetsBinding.instance.addPostFrameCallback, and (4) calls _checkForOrdinalSpend(true) from initState after super.initState(). These changes are defensive: they prevent calling setState before the widget’s first frame has built, which can throw in Flutter, and they avoid an unnecessary database read when the wallet does not support ordinals or no UTXOs are used. The commit title ‘add some safeguards’ and the absence of any exploit description suggest this is a robustness fix rather than a patch for an identified attack.
Changed components
lib/pages/send_view/confirm_transaction_view.dartFlutter UI state management for transaction confirmation screenOrdinalsInterface spend detection flowInspect captured patch +14 / −8
diff --git a/lib/pages/send_view/confirm_transaction_view.dart b/lib/pages/send_view/confirm_transaction_view.dart
index d925645..424269b 100644
--- a/lib/pages/send_view/confirm_transaction_view.dart
+++ b/lib/pages/send_view/confirm_transaction_view.dart
@@ -14,9 +14,9 @@ import 'dart:io';
import 'package:decimal/decimal.dart';
import 'package:flutter/material.dart';
-import 'package:isar_community/isar.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
+import 'package:isar_community/isar.dart';
import '../../models/input.dart';
import '../../models/isar/models/transaction_note.dart';
@@ -113,14 +113,16 @@ class _ConfirmTransactionViewState
bool _spendsOrdinal = false;
- Future<void> _checkForOrdinalSpend() async {
+ Future<void> _checkForOrdinalSpend(
+ bool updateStateInPostFrameCallback,
+ ) async {
+ final db = ref.read(mainDBProvider);
final wallet = ref.read(pWallets).getWallet(walletId);
if (wallet is! OrdinalsInterface) return;
final usedUtxos = widget.txData.usedUTXOs;
if (usedUtxos == null || usedUtxos.isEmpty) return;
- final db = ref.read(mainDBProvider);
for (final input in usedUtxos) {
if (input is! StandardInput) continue;
final ordinal = await db.isar.ordinals
@@ -133,8 +135,12 @@ class _ConfirmTransactionViewState
.utxoVOUTEqualTo(input.utxo.vout)
.findFirst();
if (ordinal != null) {
- if (mounted) {
- setState(() => _spendsOrdinal = true);
+ if (updateStateInPostFrameCallback) {
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ if (mounted) setState(() => _spendsOrdinal = true);
+ });
+ } else {
+ if (mounted) setState(() => _spendsOrdinal = true);
}
return;
}
@@ -556,6 +562,8 @@ class _ConfirmTransactionViewState
@override
void initState() {
+ super.initState();
+
isDesktop = Util.isDesktop;
walletId = widget.walletId;
routeOnSuccessName = widget.routeOnSuccessName;
@@ -567,9 +575,7 @@ class _ConfirmTransactionViewState
onChainNoteController = TextEditingController();
onChainNoteController.text = widget.txData.noteOnChain ?? "";
- super.initState();
-
- _checkForOrdinalSpend();
+ _checkForOrdinalSpend(true);
}
@override
Why this scored 23/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.