| 1 |
transaction_history_filter_cubit.dart:39-51,60-61 |
High |
USER-VISIBLE |
changeFilter passes raw partial args; changing one date silently drops the previously-set other date bound. |
| 2 |
transaction_history_filter_cubit.dart:61 |
Medium |
USER-VISIBLE |
End-date filter at midnight excludes all transactions made on the selected end day (asymmetric vs start). |
| 3 |
transaction_history_filter_cubit.dart:16,18 |
Low |
CODE-BUG |
limit declared but never forwarded; silently ignored. |
| 4 |
transaction_history_filter_state.dart:3 |
Low |
CODE-BUG |
State not Equatable → forced rebuilds, hard to assert. |
| 5 |
transaction_history_receipt_state.dart:27-31 |
Medium |
USER-VISIBLE |
Failure state omits message from props → second failure equal → error SnackBar not re-shown. |
| 6 |
transaction_history_multi_receipt_state.dart:27-31 |
Medium |
USER-VISIBLE |
Same props-omission defect as #5 for multi-receipt failure. |
| 7 |
transaction_history_page.dart:33-40,115-119 |
Medium |
CODE-BUG |
StatelessWidget owns undisposed ValueNotifiers; reset on parent rebuild (resource leak). |
| 8 |
transaction_history_page.dart:69,83 |
Low |
USER-VISIBLE |
firstDate: DateTime(2025) hardcoded → pre-2025 dates unreachable in picker. |
| 9 |
transaction_history_page.dart:52-104 |
Low |
USER-VISIBLE |
No start<=end validation and no empty-state message. |
| 10 |
transaction_history_row.dart:65 |
Low |
CODE-BUG |
InkWell with no onTap → misleading non-interactive affordance. |
| 11 |
dashboard_bloc.dart:18,43,46,54 |
Medium |
CODE-BUG |
Injected asset never read; prices hardcode global realUnitAsset (wrong asset if they diverge). |
| 12 |
dashboard_bloc.dart:45-66 |
Medium |
USER-VISIBLE |
Refresh handlers have no error handling; network failure shows blank/--.-- dashboard. |
| 13 |
dashboard_bloc.dart:35-39,68-71 |
Medium |
USER-VISIBLE |
CurrencyChanged refresh has no restartable guard → stale-currency response can win the race. |
| 14 |
balance_cubit.dart:22 |
Medium |
CODE-BUG |
watchBalance(...).listen(emit) registers no onError → balance silently frozen on stream error. |
| 15 |
dashboard_transaction_history_cubit.dart:14 |
Low |
CODE-BUG |
Stream listen with no onError (same as #14). |
| 16 |
pending_transactions_cubit.dart:14-22 |
Medium |
CODE-BUG |
Constructor fetch with no isClosed guard; catch's emit([]) throws again uncaught after close. |
| 17 |
dashboard_price_widget.dart:27 / dashboard_portfolio_chart_widget.dart:25 |
Low |
CODE-BUG |
Provider key on a List's hashCode → stale chart on hash collision. |
| 18 |
portfolio_chart.dart:26-41 vs portfolio_chart_cubit.dart:137-138,168-170 |
Low |
USER-VISIBLE |
Missing clipData: none + asymmetric band → upward spike clipped at top. |
| 19 |
price_chart_cubit.dart:69,71 / portfolio_chart_cubit.dart:76,82 |
Low |
CODE-BUG |
.first/.last assume sorted-ascending feed; no sort/guard. |
| 20 |
price_chart_cubit.dart:25-29 |
Low |
CODE-BUG |
selectPeriod emits twice → redundant intermediate rebuild. |
| 21 |
cash_holding_box.dart:26 |
Low |
USER-VISIBLE |
Raw unscaled $balance BigInt interpolated into the balance×price hint. |
| 22 |
dashboard_page.dart:113-116 |
Low |
CODE-BUG |
Redundant inner ternary; else BigInt.zero is dead code. |
| 23 |
dashboard_pending_transactions.dart:11-23 |
Low |
CODE-BUG |
DashboardPendingTransactions is dead code (unreferenced). |
| 24 |
home_state.dart:3-16 |
Medium |
CODE-BUG |
HomeState not Equatable; copyWith can't reset nullable openWallet. |
| 25 |
home_bloc.dart:55-79 |
Medium |
USER-VISIBLE |
_onLoadCurrentWallet catch emits no error state → wallet-load failure invisible (spinner just stops). |
| 26 |
home_bloc.dart:81-101 |
Medium |
CODE-BUG |
_onDeleteCurrentWallet no try/catch → stuck loading spinner + unhandled exception on throw. |
| 27 |
home_bloc.dart:113 |
Low |
CODE-BUG |
Handler typed to base HomeEvent instead of CompleteOnboardingEvent. |
| 28 |
home_bloc.dart:76-78,131-133 |
Low |
CODE-BUG |
Fire-and-forget balance/tx-sync futures; thrown future unobserved. |
| 29 |
home_page.dart:20-23 |
Low |
CODE-BUG |
Splash Image.asset has no errorBuilder → broken-image box if asset missing. |
| 30 |
time_period.dart:12-25 |
Low |
CODE-BUG |
Instance method name(context) shadows implicit EnumName.name getter → latent breakage. |
RealUnit (RealUnitCH/app) — Consolidated Bug-Audit Findings
Source: Big Brother test-agent run, 2026-06-03. 10 report-only audits over the Flutter app
at base commit
2702a2b. Each part = best (most complete) orchestrator run, perfixer-iteration-1/fixer/fix-spec.md(cross-checked againstfixer-repair-report.md).All findings are report-only (no code was changed). Classifications USER-VISIBLE / CODE-BUG
are preserved exactly as each report labelled them.
Best run chosen per part
Summary table
(Some findings are dual-classed USER-VISIBLE+CODE-BUG; they are counted under both columns,
so the UV+CB columns sum slightly above the findings total for parts 1/2/6/9/10. Per-part
findings counts are exact.)
Part 1 — Onboarding & Seed
restoreWallet()has no try/catch; persist failure freezes UI at loading spinner forever, no error/retry.isClosedguard before final emit; popping page mid-await throws StateError.createWallet()no try/catch; generation failure leaves a permanent spinner, no retry.as SoftwareWalletcast crashes on a real unlock race → infinite spinner.ensureCurrentWalletUnlocked()not wrapped; unlock failure → infinite spinner, no failure UI.createWallet()fire-and-forget void async with no concurrency guard; lifecycle cycling overlaps calls.copyWithcannot resetwalletto null (nullable-field copyWith anti-pattern).whileloop if seed length < 4 (latent; unreachable with 12-word seeds).Random()constructed inside the selection loop; wasteful and non-deterministic for tests.close()awaitslockCurrentWallet()with no try/catch → unhandled async error on teardown.Part 2 — Auth & PIN
Part 3 — Dashboard, Home & Transaction History
changeFilterpasses raw partial args; changing one date silently drops the previously-set other date bound.limitdeclared but never forwarded; silently ignored.messagefrom props → second failure equal → error SnackBar not re-shown.firstDate: DateTime(2025)hardcoded → pre-2025 dates unreachable in picker.assetnever read; prices hardcode global realUnitAsset (wrong asset if they diverge).--.--dashboard.watchBalance(...).listen(emit)registers no onError → balance silently frozen on stream error.emit([])throws again uncaught after close.clipData: none+ asymmetric band → upward spike clipped at top..first/.lastassume sorted-ascending feed; no sort/guard.selectPeriodemits twice → redundant intermediate rebuild.$balanceBigInt interpolated into the balance×price hint.else BigInt.zerois dead code.DashboardPendingTransactionsis dead code (unreferenced).openWallet._onLoadCurrentWalletcatch emits no error state → wallet-load failure invisible (spinner just stops)._onDeleteCurrentWalletno try/catch → stuck loading spinner + unhandled exception on throw.Image.assethas no errorBuilder → broken-image box if asset missing.name(context)shadows implicitEnumName.namegetter → latent breakage.Part 4 — Buy & Sell
SellBitboxErroris a dead-end blank screen with no retry; must re-sign everything.Icon(... fontWeight: ...)— invalid named arg on material Icon (analyzer/compile error).confirmPaymentemits after await without isClosed guard → StateError on unmount._fractionDigitsdecimal branch unreachable from digits-only shares path (dead logic).e.toString()surfaced to end users in snackbars (unlocalized, minor info exposure).Part 5 — KYC & Legal
dfxApprovalstep has no case → blank white screen with no way forward.e.toString()exception text surfaced verbatim to end users (minor info-leak).birthdayCtrlValueNotifier never disposed (leak).swissTaxResidence: truehardcoded unconditionally → incorrect tax-residence declaration submitted.currentIndexnot clamped after re-filtering visibleQuestions → RangeError / wrong question.visibleQuestions→elementAt(0)RangeError crash on questions page build.const TextStyle(fontSize:)violates project styling rule.(Plus 5 minor low-confidence observations O1-O5: init-order, consent-vs-next button semantics,
empty-map
.firstthrow, ignored mailto link, TnC link entity to verify.)Part 6 — Receive & Wallet Address
substringon the address → RangeError crash (hits Receive and Settings).ethereum:URI but copy yields bare address — payload mismatch (confirm intent).primaryAddressread with no readiness/empty guard → crash or blank QR when not ready.primaryAddress, never listens → stale receive address on account switch.TextStyleviolates project styling overlay.context.pop()with no canPop check → could trap user on root/deep-link.Part 7 — Hardware Wallet / BitBox
init()on the shared BitBox SDK manager → pairing wedge.checkForBitbox()awaitsgetAllUsbDevices()in a periodic timer with no try/catch → unhandled async error.'Luke-Skywallet'persisted and shown for paired BitBox._pendingInit!force-unwrap relies on an unenforced invariant.connectToBitboxre-entry guard only checks BitboxConnecting.vnormalization doesn't handle a legacy 27/28 recovery id → invalidv, rejected tx.signToSignatureassumes the native signature buffer is >=65 bytes → RangeError on short buffer.height*0.8bottom sheet can overflow / clip buttons on small screens.catch (e)in_captureAuthSignatureswallows non-Exception Errors, masking real bugs.initreturn didInitis dead.BitboxFoundbase state momentarily renders the generic default UI (cosmetic flash)._disconnectAndForgetonly catcheson Exception; a thrown Error escapes the periodic timer.Part 8 — Settings & Support
SettingsTaxReportFailureomits props → all failures Equatable-equal (latent error de-dup).OpenFile.openresult ignored → silent no-op if PDF can't be opened._DatePickerModelValueNotifier on StatelessWidget, never disposed; resets on rebuild.firstDate: DateTime(2025)hardcoded → pre-2025 report dates unreachable._onSetNetworkModeEventno error handling: repo mutated pre-await; failure hangs network-page spinner._loadingModelValueNotifier on StatelessWidget, never disposed.getUserDataemits after awaits with no isClosed guard → StateError if page popped mid-load._BitboxDisconnectedViewcallsonReconnected()after await with no mounted check.e.toString()shown to users; no ApiException.message path._formatTimeusesadd(timeZoneOffset)nottoLocal()→ wrong time across DST / non-UTC._getTicketNamehardcoded English, not localized.selectReasonis dead code (reason auto-set to.other).javaScriptEnabled:false+ in-app realunit.ch with no external-browser button → blank, no escape.launchUrl(tel:/mailto:)unawaited/unchecked → silent no-op / unhandled async error.context.read<HomeBloc>()→ stale if wallet changes.hideAmountsin state but never persisted/restored → resets on bloc recreation.Part 9 — Core packages
deleteWalletdeletes account rows but NOT the walletInfos row holding the encrypted seed → deleted seed survives on disk.BigInt.from(double*100)truncates toward zero → prices/portfolio off by a cent.DEregardless of user locale.ensureCurrentWalletUnlockedholder-count leak on a throwing unlock → mnemonic stays resident.SellPaymentInfo.amounttruncates a double → fractional sells blocked by EIP-7702 amount check.height:0→ height-based incremental sync cursor never advances.asShortTxIdRangeError on strings shorter than 10 chars (public extension).?if url already has query).decryptSeeddoesn't validate:separator →substring(0,-1)RangeError on malformed input.updateBalanceswallows all errors with only a debug log; masks real regressions.updateAssetalways nulls icon → stale decimals/symbol.EthereumURIis not EIP-681 (no value/wei, no @ChainID) → external scanners may misread.PRAGMA foreign_keys=ONnever run → not enforced.Part 10 — Cross-cutting
getFromChainIdfirstWhereno orElse → StateError for any unknown chainId (crashes history/icon).fromCodefirstWhere no orElse → StateError on unknown code at unguarded buy/sell DTO call sites; Language also case-sensitive.split('-')index → RangeError on malformed stored value.state.extra as <Type>non-null casts crash on missing extra; no errorBuilder/redirect.getAssetImagePathdefault returns REALU.png → ZCHF/Sepolia-ETH/unknown assets show RealUnit logo.?, re-breaks BitBox registration.TapGestureRecognizercreated in build, never disposed → leak per rebuild.initialDate, never the picked date (relies on parent rebuild).--.--(looks like missing data); symbol/spacing inconsistencies.trailinghas no Expanded/ellipsis → long value RenderFlex overflow.brand700lighter thanbrand200— inverted shade (likely swapped value).DeviceInfo.instanceallocates a new object each access despite singleton intent.tabCount==0→ 1/0 Infinity layout; unknown selectedTab → indicator off-screen.normalizeregex edge cases (.5mmno match;123.mmFormatException)._onResumedruns unconditionally (pre-wallet/locked) → may throw or trigger spurious network calls.Icon(null)or hides provided icon.Grand totals
P3 chore: typo in *_repository.dart #1; P4 BB1, S1; P5 F6; P6 F1; P7 F1; P9 H1 — plus borderline Medium-High P4 BB2, P7 F2,
P9 H2 not included in the 9).
Top user-visible bugs (HIGH-severity, USER-VISIBLE, across all parts)
restore_wallet_cubit.dart:18-41)setup_pin_cubit.dart:43-77)transaction_history_filter_cubit.dart:39-51)sell_bitbox_cubit.dart:168-182)sell_converter_cubit.dart:90)swissTaxResidence: truehardcoded on every KYC registration submit → incorrect tax-residence declaration (labelled CODE-BUG, High compliance impact). (kyc_registration_page.dart:280)substringon the wallet address → RangeError crash on Receive and Settings screens (CODE-BUG → USER-VISIBLE crash). (qr_address_widget.dart:42-55)init()on the shared SDK manager → pairing wedge (CODE-BUG, user-visible pairing failure). (connect_bitbox_cubit.dart:45-92)deleteWalletnever deletes the encrypted seed row → "deleted" wallet's seed survives on disk (USER-VISIBLE + CODE-BUG, privacy/data-retention). (wallet_storage.dart:28-29)Notes on data completeness
fix-spec.md(Architect) contained only the auditmethod/scope, not the bug table; the full 19-finding inventory was taken from that run's
fixer-repair-report.md(Repair agent). All other parts' findings came fromfix-spec.md.fix-spec.mdcarries the complete 21-row classified summary table(id, file:line, class, severity, visibility); the prose detail lives in a sibling
audit-findings.md. Descriptions here are summarized from the table + category column.shorter complete runs) were discarded in favour of the most-populated run per part.