Skip to content

feat: Cashu improvements#653

Open
frnandu wants to merge 14 commits into
masterfrom
feat/cashu-improvements
Open

feat: Cashu improvements#653
frnandu wants to merge 14 commits into
masterfrom
feat/cashu-improvements

Conversation

@frnandu

@frnandu frnandu commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • New Features

    • Cashu wallet export/import (JSON) and on-device restore
    • Reclaim pending funds flows and UI actions
    • Seed-phrase backup/confirm banner and backup/restore dialogs
  • Improvements

    • Wallet action menu now exposes backup/restore and reclaim actions
    • App loads Cashu seed from secure storage at startup
    • LNURL wallet labels clarified to “Lightning Address (LNURL)”
  • Localization

    • New/updated translations across EN, DE, ES, FR, IT, JA, PL, PT, RU, ZH, FI
  • Tests

    • Added export/import unit tests for Cashu state

feat: add reclaim triggers for cashu pending transactions
feat: add backup/restore of cash seed & db proofs
@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@1-leo, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 12 minutes and 27 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2df8c2ae-bd0b-4550-9080-409ab656710a

📥 Commits

Reviewing files that changed from the base of the PR and between 4de27db and b979d74.

📒 Files selected for processing (5)
  • packages/ndk/lib/domain_layer/usecases/cashu/cashu.dart
  • packages/ndk/lib/domain_layer/usecases/cashu/cashu_export_import.dart
  • packages/ndk/test/cashu/wallet_transaction_model_test.dart
  • packages/ndk_flutter/lib/repositories/cashu_seed_store.dart
  • packages/ndk_flutter/lib/widgets/wallets/n_cashu_seed_backup_warning.dart
📝 Walkthrough

Walkthrough

Adds Cashu state export/import with JSON map/string APIs, wires those into Cashu and the ndk barrel, implements persistent Cashu seed storage and a one-time backup warning UI, refactors wallet action dialogs into a reusable mixin (reclaim/backup/restore/send/receive flows), extends transaction models for serialization, expands localization for backup/restore flows, and updates the sample app and Android toolchain.

Changes

Cashu export/import engine and public wiring

Layer / File(s) Summary
Export/import engine, transaction models, and tests
packages/ndk/lib/domain_layer/usecases/cashu/cashu_export_import.dart, packages/ndk/lib/data_layer/models/wallet_transaction_model.dart, packages/ndk/test/cashu/cashu_import_export_test.dart
CashuStateExportImport provides typed versioned export/import with optional seed phrase and transaction history. WalletTransactionModel and subclass models serialize/deserialize wallet transactions by wallet type. Tests validate round-trip and invalid payload rejection.
Cache decorator synchronization and Cashu public API
packages/ndk/lib/domain_layer/usecases/cashu/cashu_cache_decorator.dart, packages/ndk/lib/domain_layer/usecases/cashu/cashu.dart, packages/ndk/lib/ndk.dart
Cache decorator adds mutex-synchronized methods for mint info and counter access. Cashu class wires CashuStateExportImport and exposes four public export/import methods that refresh balances post-import. Use-case exported from ndk barrel.

Seed storage, backup warning widget, and wallet list integration

Layer / File(s) Summary
Secure seed phrase storage repository
packages/ndk_flutter/lib/repositories/cashu_seed_store.dart
CashuSeedStore uses FlutterSecureStorage to load-or-generate 12-word BIP39 seed phrases on first run, read/write existing phrases, and track backup confirmation status separately.
Seed backup warning widget and integration
packages/ndk_flutter/lib/widgets/wallets/n_cashu_seed_backup_warning.dart, packages/ndk_flutter/lib/widgets/wallets/n_wallets.dart, packages/ndk_flutter/lib/widgets/widgets.dart, packages/ndk_flutter/lib/ndk_flutter.dart
NCashuSeedBackupWarning displays a one-time amber banner when a Cashu wallet exists and seed backup is not yet confirmed. On tap, shows dialog with seed words, copy-to-clipboard action, and confirmation checkbox. Updates persistent store on confirmation. Integrated into wallet-list layouts and exported via barrels.

Wallet action dialogs and dialog orchestration mixin

Layer / File(s) Summary
Reclaim pending funds discovery and dialog UI
packages/ndk_flutter/lib/widgets/wallets/wallet_action_dialogs.dart
reclaimablePending() filters transactions to Cashu funding transactions with complete quote/method/keyset info. showReclaimDialog() renders alert with ReclaimPendingTile widgets driven by retrieveFunds() streams that display pending/completed/failed status with error reasons or completion values.
WalletActionDialogsMixin base and backup/restore
packages/ndk_flutter/lib/widgets/wallets/wallet_action_dialogs.dart
WalletActionDialogsMixin<T extends StatefulWidget> provides error/success snackbars, receive-flow routing by wallet type, and showReclaimPending(). showBackupDialog() generates Cashu backup JSON via export API, displays in scrollable block, and copies to clipboard. showRestoreDialog() validates and restores from user-pasted JSON.
Send/receive and invoice tracking dialogs
packages/ndk_flutter/lib/widgets/wallets/wallet_action_dialogs.dart
Implements showSendDialog() with wallet-type branching, Cashu token send (amount input → initiateSpend → clipboard), invoice pay (Cashu initiateRedeem stream or NWC send), Cashu token receive (validate → receive() stream), invoice creation (Cashu initiateFund or NWC wallets.receive), and two invoice tracking flows (Cashu with QR and redeem stream; generic with close/copy actions).

Wallet widgets adopt dialog mixin and UI updates

Layer / File(s) Summary
NWalletActions refactor to mixin-based dialogs
packages/ndk_flutter/lib/widgets/wallets/n_wallet_actions.dart
Refactored from inline dialog logic to WalletActionDialogsMixin delegation. Adds optional onClearSelection, showTitle, showCloseButton, and condensed flags for flexible header/card rendering. Send/receive handlers call mixin methods instead of private _show*.
NWalletCard menu actions and NPendingTransactions reclaim
packages/ndk_flutter/lib/widgets/wallets/n_wallet_card.dart, packages/ndk_flutter/lib/widgets/wallets/n_pending_transactions.dart
NWalletCard mixes in mixin, builds popup actionItems (send/receive + Cashu reclaim/backup/restore), and routes selections to mixin methods. NPendingTransactions adds header reclaim button and per-card overlay buttons computed via reclaimablePending().

Localization interface, keys, and implementations

Layer / File(s) Summary
AppLocalizations interface additions
packages/ndk_flutter/lib/l10n/app_localizations.dart
Adds abstract getters for backup/reclaim/restore seed warning/title/instructions/confirmation/done, reclaim pending labels, backup/restore actions, Cashu backup/restore dialogs, backup JSON UI text, and restoreSuccess(int count) method.
ARB translation keys across locales
packages/ndk_flutter/lib/l10n/app_*.arb (multiple locales)
Adds new translation keys for seed backup flow, reclaim pending funds, and wallet backup/restore UI. English includes extended backup/restore dialog strings and {count} placeholder for restore success message.
Per-locale AppLocalizations implementations
packages/ndk_flutter/lib/l10n/app_localizations_*.dart (multiple locales)
Adds getter overrides and restoreSuccess(int count) implementations to return translated strings from .arb files for each locale.

Sample app runtime initialization and Android toolchain updates

Layer / File(s) Summary
Runtime seed loading and locale wiring
packages/sample-app/lib/demo_app_config.dart, packages/sample-app/lib/main.dart
Removes hardcoded cashuSeedPhrase constant. Loads/creates seed at startup via CashuSeedStore().loadOrCreate() and applies to NDK config. Switches supported locales to ndk_flutter.AppLocalizations.supportedLocales.
Android SDK, NDK, Kotlin, Gradle version bumps
packages/sample-app/android/*
Raises compileSdkVersion to 36, updates NDK, bumps Kotlin, Android Gradle plugin, Gradle Wrapper, and adds Flutter-migrator gradle flags.

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested labels: enhancement

Suggested reviewers:

  • nogringo
  • 1-leo

🐰 A backup so secure, the seed words clear,
Restore with ease, no wallet fear!
Reclaim what's pending, with just one tap,
Multi-locale magic closes the gap.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/cashu-improvements

@frnandu frnandu requested a review from 1-leo June 9, 2026 16:42

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 19

🧹 Nitpick comments (3)
packages/sample-app/android/gradle/wrapper/gradle-wrapper.properties (1)

5-5: ⚡ Quick win

Consider aligning Gradle version with ndk_flutter module.

The sample-app is using Gradle 8.11.1, while the packages/ndk_flutter/android/gradle/wrapper/gradle-wrapper.properties uses Gradle 8.14 (see context snippet 1). Using different Gradle versions across modules in the same repository can lead to inconsistent build behavior and subtle issues.

Consider updating to Gradle 8.14 for consistency:

📦 Suggested version alignment
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/sample-app/android/gradle/wrapper/gradle-wrapper.properties` at line
5, Update the distributionUrl in
packages/sample-app/android/gradle/wrapper/gradle-wrapper.properties (the
distributionUrl property currently set to gradle-8.11.1-all.zip) to use Gradle
8.14 (match packages/ndk_flutter's gradle-wrapper.properties) so both modules
use the same Gradle version; modify the distributionUrl value to point to the
gradle-8.14-all.zip distribution.
packages/ndk_flutter/lib/l10n/app_en.arb (1)

1156-1162: ⚡ Quick win

Add ARB metadata for backupSeed* keys to preserve translator context.

backupSeedWarning, backupSeedTitle, backupSeedInstructions, backupSeedConfirm, and backupSeedDone are missing @...description entries, unlike the neighboring new keys. Adding descriptions keeps localization generation/docs consistent and reduces ambiguity for translators.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ndk_flutter/lib/l10n/app_en.arb` around lines 1156 - 1162, Add ARB
metadata description entries for the missing keys backupSeedWarning,
backupSeedTitle, backupSeedInstructions, backupSeedConfirm, and backupSeedDone
so translators have context; for each key add a corresponding "@<key>" JSON
string giving a short description/purpose and any notes (e.g., whether it's a
title, button label, or instructional text) consistent with neighboring metadata
entries like the ones around reclaimPendingFunds/reclaimPendingTitle so
localization generation and docs remain consistent.
packages/ndk_flutter/lib/l10n/app_localizations.dart (1)

2214-2290: 🏗️ Heavy lift

Complete non-English translations for the newly introduced backup/restore contract keys.

These new keys are in the public localization interface, but in the provided locale ARBs only English has the full backup/restore set (backup, restore, cashuBackupTitle, cashuBackupWarning, generatingBackup, copyBackup, backupCopiedToClipboard, cashuRestoreTitle, backupJson, backupJsonHint, pleaseEnterBackup, restoringBackup, restoreSuccess). This will show mixed English UI in backup/restore dialogs for non-English locales.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ndk_flutter/lib/l10n/app_localizations.dart` around lines 2214 -
2290, The new localization getters (backup, restore, cashuBackupTitle,
cashuBackupWarning, generatingBackup, copyBackup, backupCopiedToClipboard,
cashuRestoreTitle, backupJson, backupJsonHint, pleaseEnterBackup,
restoringBackup, and restoreSuccess) are only defined in English ARB — causing
mixed-language UI for other locales; add these keys with appropriate
translations to each non-English ARB, ensure restoreSuccess(int count) has
correct plural/placeholder syntax for those locales, then re-run the project's
localization generation (e.g., flutter gen-l10n or your intl generator) so the
generated AppLocalizations includes the new strings for all locales.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/ndk_flutter/lib/l10n/app_localizations_de.dart`:
- Around line 1097-1137: All of the new overrides in app_localizations_de.dart
(backup, restore, cashuBackupTitle, cashuBackupWarning, generatingBackup,
copyBackup, backupCopiedToClipboard, cashuRestoreTitle, backupJson,
backupJsonHint, pleaseEnterBackup, restoringBackup, and restoreSuccess) are
still in English; replace each English string with proper German translations
(and update the restoreSuccess(int count) return string to use correct German
pluralization/wording) so the German localization is fully localized rather than
showing mixed-language UI.

In `@packages/ndk_flutter/lib/l10n/app_localizations_es.dart`:
- Around line 1098-1138: The Spanish localization class contains English strings
for backup/restore UI; update the getters and the restoreSuccess(int count)
method in app_localizations_es.dart (symbols: backup, restore, cashuBackupTitle,
cashuBackupWarning, generatingBackup, copyBackup, backupCopiedToClipboard,
cashuRestoreTitle, backupJson, backupJsonHint, pleaseEnterBackup,
restoringBackup, restoreSuccess) to Spanish translations so the UI is fully
localized; keep the same method/getter names and interpolation in restoreSuccess
but replace the returned text with the correct Spanish phrasing.

In `@packages/ndk_flutter/lib/l10n/app_localizations_fi.dart`:
- Around line 1095-1135: The Finnish localization file has untranslated English
strings in the generated class (see getters backup, restore, cashuBackupTitle,
cashuBackupWarning, generatingBackup, copyBackup, backupCopiedToClipboard,
cashuRestoreTitle, backupJson, backupJsonHint, pleaseEnterBackup,
restoringBackup and the restoreSuccess(int) message); update the corresponding
keys in app_fi.arb with proper Finnish translations for each of these entries
and then regenerate the localization files (run your localization generation
tool) so the generated AppLocalizationsFi class contains Finnish text instead of
English literals.

In `@packages/ndk_flutter/lib/l10n/app_localizations_fr.dart`:
- Around line 1098-1138: The French localization class AppLocalizationsFr
contains untranslated English strings for keys/methods backup, restore,
cashuBackupTitle, cashuBackupWarning, generatingBackup, copyBackup,
backupCopiedToClipboard, cashuRestoreTitle, backupJson, backupJsonHint,
pleaseEnterBackup, restoringBackup and restoreSuccess; update these keys in
app_fr.arb with proper French translations (including plural/interpolated form
for restoreSuccess) and then regenerate the Dart localization files so
AppLocalizationsFr reflects the translated text.

In `@packages/ndk_flutter/lib/l10n/app_localizations_it.dart`:
- Around line 1099-1139: The Italian localization entries for backup/restore are
still in English; update the corresponding keys in app_it.arb (backup, restore,
cashuBackupTitle, cashuBackupWarning, generatingBackup, copyBackup,
backupCopiedToClipboard, cashuRestoreTitle, backupJson, backupJsonHint,
pleaseEnterBackup, restoringBackup, restoreSuccess) with proper Italian
translations, then run the localization generation tool to regenerate
AppLocalizationsIt (so the class and its getters/methods reflect the Italian
strings).

In `@packages/ndk_flutter/lib/l10n/app_localizations_ja.dart`:
- Around line 1084-1124: The Japanese localization file AppLocalizationsJa
contains English strings for backup/restore (methods/gets: backup, restore,
cashuBackupTitle, cashuBackupWarning, generatingBackup, copyBackup,
backupCopiedToClipboard, cashuRestoreTitle, backupJson, backupJsonHint,
pleaseEnterBackup, restoringBackup and function restoreSuccess), so update
app_ja.arb with proper Japanese translations for each corresponding key
(matching these symbol names) and then regenerate the Dart localization stubs
(run the Flutter gen-l10n/localization generation) so AppLocalizationsJa returns
the Japanese text instead of the English literals.

In `@packages/ndk_flutter/lib/l10n/app_localizations_pl.dart`:
- Around line 1097-1137: The Polish translations for the backup/restore strings
are missing in AppLocalizationsPl (fields/methods: backup, restore,
cashuBackupTitle, cashuBackupWarning, generatingBackup, copyBackup,
backupCopiedToClipboard, cashuRestoreTitle, backupJson, backupJsonHint,
pleaseEnterBackup, restoringBackup, restoreSuccess); update the corresponding
keys in app_pl.arb with proper Polish translations for each key (including the
plural/parameterized restoreSuccess) and then regenerate the Dart localization
files so AppLocalizationsPl is rebuilt with the translated strings.

In `@packages/ndk_flutter/lib/l10n/app_localizations_pt.dart`:
- Around line 1101-1141: AppLocalizationsPt currently exposes English texts for
the backup/restore keys (methods/props like backup, restore, cashuBackupTitle,
cashuBackupWarning, generatingBackup, copyBackup, backupCopiedToClipboard,
cashuRestoreTitle, backupJson, backupJsonHint, pleaseEnterBackup,
restoringBackup, restoreSuccess) so pt_BR ends up inheriting English; add
correct Portuguese translations for these keys in app_pt.arb (and app_pt_BR.arb
if you want region-specific variants) and then regenerate the Flutter
localization files (flutter gen-l10n) so AppLocalizationsPt and
AppLocalizationsPtBr contain the localized strings instead of the current
English ones.

In `@packages/ndk_flutter/lib/l10n/app_localizations_ru.dart`:
- Around line 1096-1136: AppLocalizationsRu currently contains English strings
for backup/restore (properties: backup, restore, cashuBackupTitle,
cashuBackupWarning, generatingBackup, copyBackup, backupCopiedToClipboard,
cashuRestoreTitle, backupJson, backupJsonHint, pleaseEnterBackup,
restoringBackup and method restoreSuccess(int)), so update app_ru.arb with
proper Russian translations for each corresponding key and then run the
localization generation step (e.g., Flutter gen_l10n or your project's
localization script) to regenerate AppLocalizationsRu so the class contains the
Russian text instead of English.

In `@packages/ndk_flutter/lib/l10n/app_localizations_zh.dart`:
- Around line 1083-1123: The backup/restore strings in AppLocalizationsZh (e.g.,
getters backup, restore, cashuBackupTitle, cashuBackupWarning, generatingBackup,
copyBackup, backupCopiedToClipboard, cashuRestoreTitle, backupJson,
backupJsonHint, pleaseEnterBackup, restoringBackup and the method
restoreSuccess) are still in English; update their translations by adding
Chinese equivalents into the app_zh.arb resource file for each corresponding
key, then run the localization generation (e.g., Flutter gen-l10n or your i18n
build script) to regenerate the AppLocalizationsZh class so the Dart file
contains the proper Chinese strings.

In `@packages/ndk_flutter/lib/l10n/app_pt.arb`:
- Around line 288-290: The new pt locale strings use Brazilian Portuguese
phrasing; update the three keys backupSeedInstructions, backupSeedConfirm, and
backupSeedDone in app_pt.arb to European Portuguese equivalents (e.g., use
"Anote estas palavras pela ordem e guarde‑as num local seguro. São a única forma
de recuperar os seus fundos cashu se perder este equipamento." for
backupSeedInstructions, "Anotei a minha frase de recuperação e guardei‑a em
segurança" for backupSeedConfirm, and "Backup concluído" or "Já efetuei o
backup" for backupSeedDone) so the wording, pronouns, and terms (e.g.,
"equipamento" vs "dispositivo", "num local" vs "em um lugar") match pt-PT
conventions.

In `@packages/ndk_flutter/lib/repositories/cashu_seed_store.dart`:
- Around line 15-23: The backed-up flag is currently a single static key
(_backedUpKey) while CashuSeedStore allows custom _seedKey, causing cross-seed
collisions; change the implementation to derive a per-instance backup key (e.g.,
compute a backedUpKey using the instance _seedKey like "${_seedKey}_backed_up"
or provide a getter) instead of the static const _backedUpKey, and update all
uses in CashuSeedStore methods (the getters/setters that read/write the backup
flag around lines 47-52) to use this instance-backedUpKey so each seed namespace
has its own backup status.

In `@packages/ndk_flutter/lib/widgets/wallets/n_wallets.dart`:
- Line 160: The NWallets widget currently constructs NCashuSeedBackupWarning
without supplying a seedStore, hardcoding the default seed-store wiring and
preventing apps with custom seed keys from aligning backup-status storage;
modify NWallets to accept an optional seedStore (or use the existing seedStore
on widget.ndkFlutter if available) and forward it into both
NCashuSeedBackupWarning(...) instances via the seedStore constructor parameter
so the banner reads/writes backup status from the app-provided store rather than
the hardcoded default.

In `@packages/ndk_flutter/lib/widgets/wallets/wallet_action_dialogs.dart`:
- Around line 21-23: The reclaimablePending filter allows empty usedKeysets
which later causes a runtime dereference of the first keyset; update the filter
that checks tx.usedKeysets (in the reclaimablePending predicate) to require a
non-empty list (e.g., tx.usedKeysets != null && tx.usedKeysets.isNotEmpty) so
empty arrays are rejected before reclaim logic access tx.usedKeysets[0].
- Around line 850-852: The post-frame callback unconditionally calls
Navigator.of(dialogContext).pop(), which can run after the dialog was disposed;
guard the pop by checking the navigator state is still mounted and canPop before
calling pop (e.g. use Navigator.of(dialogContext) to get the NavigatorState and
verify mounted && canPop()), and only then call pop and show the snackbar (leave
scaffoldMessenger.showSnackBar as-is but run it inside the same guarded block).

In `@packages/ndk/lib/domain_layer/usecases/cashu/cashu_backup.dart`:
- Around line 179-251: importFromMap currently applies side effects while
parsing, risking partial restores; first fully parse and validate the entire
payload into local in-memory structures (e.g., restoredSeedPhrase string,
List<CashuMintInfo> mintInfos, List<CahsuKeyset> keysets,
Map<String,List<CashuProof>> proofsByMint, List<counter maps>, List<Transaction>
parsedTransactions) without calling mutating APIs, then if validation passes
perform the persistence/side-effect phase in order: call
_cashuSeed.setSeedPhrase (only if restoreSeedPhrase), then
_cacheManager.saveMintInfo for each CashuMintInfo, _cacheManagerCashu.saveKeyset
for each CahsuKeyset, _cacheManagerCashu.saveProofs per proofsByMint entry,
_cacheManager.setCashuSecretCounter for each counter, and finally
_walletsRepo.saveTransactions with parsedTransactions; ensure any parse errors
abort before any of those mutating calls.

In `@packages/ndk/lib/domain_layer/usecases/cashu/cashu.dart`:
- Around line 149-176: Both importBackup and importBackupJsonString refresh only
balances; after the import (i.e., after
_cashuBackup.importFromMap/_cashuBackup.importFromJsonString and
_updateBalances()), also refresh and push restored transactions into the
transaction subjects so subscribers see updates — call the internal routine that
loads/publishes transactions (or implement one) and ensure it updates
pendingTransactions and latestTransactions subjects (e.g., invoke
_updateTransactions() or explicitly add/publish to pendingTransactions and
latestTransactions) in both importBackup and importBackupJsonString.

In `@packages/sample-app/android/build.gradle`:
- Line 2: The Kotlin version declaration ext.kotlin_version = '2.3.21' must be
validated for compatibility with the Kotlin Gradle Plugin, Gradle, AGP and the
JVM toolchain and kept consistent across Android modules; verify that Kotlin
2.3.21 is the intended released target, update the Kotlin Gradle plugin
dependency and any module-level Kotlin version pins (e.g.,
packages/ndk_flutter/android/build.gradle) to the same compatible version or
explicitly document why a different version is required, and ensure the project
Gradle and Android Gradle Plugin versions and JDK/toolchain meet Kotlin 2.3.21
compatibility before merging.

In `@packages/sample-app/lib/main.dart`:
- Around line 46-49: The Cashu seed initialization can throw before runApp, so
wrap the call to CashuSeedStore().loadOrCreate() in a try/catch and on error set
cashuSeedPhrase to null (or a safe fallback) instead of letting the exception
bubble; ensure the variable passed to runApp (cashuUserSeedphrase) uses this
guarded value. Do the same guarding for the other initialization site referenced
(the lines around the second loadOrCreate call), and ensure downstream code that
consumes cashuUserSeedphrase tolerates null (degrade behavior) so the app can
still boot.

---

Nitpick comments:
In `@packages/ndk_flutter/lib/l10n/app_en.arb`:
- Around line 1156-1162: Add ARB metadata description entries for the missing
keys backupSeedWarning, backupSeedTitle, backupSeedInstructions,
backupSeedConfirm, and backupSeedDone so translators have context; for each key
add a corresponding "@<key>" JSON string giving a short description/purpose and
any notes (e.g., whether it's a title, button label, or instructional text)
consistent with neighboring metadata entries like the ones around
reclaimPendingFunds/reclaimPendingTitle so localization generation and docs
remain consistent.

In `@packages/ndk_flutter/lib/l10n/app_localizations.dart`:
- Around line 2214-2290: The new localization getters (backup, restore,
cashuBackupTitle, cashuBackupWarning, generatingBackup, copyBackup,
backupCopiedToClipboard, cashuRestoreTitle, backupJson, backupJsonHint,
pleaseEnterBackup, restoringBackup, and restoreSuccess) are only defined in
English ARB — causing mixed-language UI for other locales; add these keys with
appropriate translations to each non-English ARB, ensure restoreSuccess(int
count) has correct plural/placeholder syntax for those locales, then re-run the
project's localization generation (e.g., flutter gen-l10n or your intl
generator) so the generated AppLocalizations includes the new strings for all
locales.

In `@packages/sample-app/android/gradle/wrapper/gradle-wrapper.properties`:
- Line 5: Update the distributionUrl in
packages/sample-app/android/gradle/wrapper/gradle-wrapper.properties (the
distributionUrl property currently set to gradle-8.11.1-all.zip) to use Gradle
8.14 (match packages/ndk_flutter's gradle-wrapper.properties) so both modules
use the same Gradle version; modify the distributionUrl value to point to the
gradle-8.14-all.zip distribution.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b6727b6c-c134-4545-84d3-1e6c30724ee6

📥 Commits

Reviewing files that changed from the base of the PR and between 2452e67 and a105f59.

⛔ Files ignored due to path filters (1)
  • packages/sample-app/pubspec.lock is excluded by !**/*.lock
📒 Files selected for processing (44)
  • packages/ndk/lib/domain_layer/usecases/cashu/cashu.dart
  • packages/ndk/lib/domain_layer/usecases/cashu/cashu_backup.dart
  • packages/ndk/lib/ndk.dart
  • packages/ndk/test/cashu/cashu_backup_test.dart
  • packages/ndk_flutter/lib/l10n/app_de.arb
  • packages/ndk_flutter/lib/l10n/app_en.arb
  • packages/ndk_flutter/lib/l10n/app_es.arb
  • packages/ndk_flutter/lib/l10n/app_fi.arb
  • packages/ndk_flutter/lib/l10n/app_fr.arb
  • packages/ndk_flutter/lib/l10n/app_it.arb
  • packages/ndk_flutter/lib/l10n/app_ja.arb
  • packages/ndk_flutter/lib/l10n/app_localizations.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_de.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_en.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_es.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_fi.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_fr.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_it.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_ja.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_pl.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_pt.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_ru.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_zh.dart
  • packages/ndk_flutter/lib/l10n/app_pl.arb
  • packages/ndk_flutter/lib/l10n/app_pt.arb
  • packages/ndk_flutter/lib/l10n/app_pt_BR.arb
  • packages/ndk_flutter/lib/l10n/app_ru.arb
  • packages/ndk_flutter/lib/l10n/app_zh.arb
  • packages/ndk_flutter/lib/ndk_flutter.dart
  • packages/ndk_flutter/lib/repositories/cashu_seed_store.dart
  • packages/ndk_flutter/lib/widgets/wallets/n_cashu_seed_backup_warning.dart
  • packages/ndk_flutter/lib/widgets/wallets/n_pending_transactions.dart
  • packages/ndk_flutter/lib/widgets/wallets/n_wallet_actions.dart
  • packages/ndk_flutter/lib/widgets/wallets/n_wallet_card.dart
  • packages/ndk_flutter/lib/widgets/wallets/n_wallets.dart
  • packages/ndk_flutter/lib/widgets/wallets/wallet_action_dialogs.dart
  • packages/ndk_flutter/lib/widgets/widgets.dart
  • packages/sample-app/android/app/build.gradle
  • packages/sample-app/android/build.gradle
  • packages/sample-app/android/gradle.properties
  • packages/sample-app/android/gradle/wrapper/gradle-wrapper.properties
  • packages/sample-app/android/settings.gradle
  • packages/sample-app/lib/demo_app_config.dart
  • packages/sample-app/lib/main.dart
💤 Files with no reviewable changes (1)
  • packages/sample-app/lib/demo_app_config.dart

Comment thread packages/ndk_flutter/lib/l10n/app_localizations_de.dart
Comment thread packages/ndk_flutter/lib/l10n/app_localizations_es.dart
Comment thread packages/ndk_flutter/lib/l10n/app_localizations_fi.dart
Comment thread packages/ndk_flutter/lib/l10n/app_localizations_fr.dart
Comment thread packages/ndk_flutter/lib/l10n/app_localizations_it.dart
Comment on lines +850 to +852
WidgetsBinding.instance.addPostFrameCallback((_) {
Navigator.of(dialogContext).pop();
scaffoldMessenger.showSnackBar(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Guard post-frame dialog pop with mounted check.

The callback can run after dialog disposal. Popping unconditionally risks navigator errors or popping the wrong route.

Patch
                       WidgetsBinding.instance.addPostFrameCallback((_) {
-                        Navigator.of(dialogContext).pop();
+                        if (!dialogContext.mounted) return;
+                        Navigator.of(dialogContext).pop();
                         scaffoldMessenger.showSnackBar(
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
WidgetsBinding.instance.addPostFrameCallback((_) {
Navigator.of(dialogContext).pop();
scaffoldMessenger.showSnackBar(
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!dialogContext.mounted) return;
Navigator.of(dialogContext).pop();
scaffoldMessenger.showSnackBar(
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ndk_flutter/lib/widgets/wallets/wallet_action_dialogs.dart` around
lines 850 - 852, The post-frame callback unconditionally calls
Navigator.of(dialogContext).pop(), which can run after the dialog was disposed;
guard the pop by checking the navigator state is still mounted and canPop before
calling pop (e.g. use Navigator.of(dialogContext) to get the NavigatorState and
verify mounted && canPop()), and only then call pop and show the snackbar (leave
scaffoldMessenger.showSnackBar as-is but run it inside the same guarded block).

Comment thread packages/ndk/lib/domain_layer/usecases/cashu/cashu.dart Outdated
@@ -1,5 +1,5 @@
buildscript {
ext.kotlin_version = '2.1.0'
ext.kotlin_version = '2.3.21'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

Is Kotlin version 2.3.21 available and what are its compatibility requirements?

💡 Result:

Yes—Kotlin 2.3.21 is available. JetBrains’ official release tag shows “Kotlin 2.3.21” published on 2026-04-23 [1], and the Kotlin release process documentation lists “2.3.21” as a bug-fix release released April 23, 2026 [2]. Compatibility requirements (what you need to match when using 2.3.21): 1) Use the Kotlin Gradle plugin (KGP) version that matches Kotlin 2.3.21. - Kotlin’s Multiplatform compatibility guide instructs you to check compatibility of the Kotlin Multiplatform Gradle plugin version (the same as the Kotlin version in your project) with Gradle, Xcode, and Android Gradle plugin versions [3]. 2) Kotlin Multiplatform: check KGP ↔ Gradle/Xcode/AGP version compatibility for the 2.3.20–2.3.21 range. - The same compatibility guide explicitly includes a section covering “2.3.20–2.3.21” for Gradle/Xcode/Android Gradle plugin compatibility checks [3]. 3) JVM builds (and any Kotlin/JVM compile): ensure your project’s JVM target/toolchain settings are consistent with the Gradle JDK/toolchain you’re using. - Kotlin’s Gradle configuration documentation notes default JVM target translation behavior and warns about mismatches between jvmTarget/Java targetCompatibility and the JDK used by the build; it recommends configuring a toolchain or aligning JVM versions to avoid incompatibility [4]. What I could not find as a single simple “minimum Gradle/JDK version” statement specifically for 2.3.21 in the sources retrieved: the authoritative place to get exact minimum/maximum supported versions is the official compatibility guide (it’s organized by Kotlin/KGP version ranges, including 2.3.20–2.3.21) [3].

Citations:


Confirm Kotlin 2.3.21 release and validate Gradle/JDK/AGP compatibility (and align modules)

ext.kotlin_version = '2.3.21'

Kotlin 2.3.21 is a published JetBrains release. Compatibility depends on using the matching Kotlin Gradle plugin (KGP) / Kotlin version and ensuring your Gradle + Android Gradle Plugin (AGP) + JVM toolchain/JDK are aligned with Kotlin’s compatibility guidance (Kotlin Multiplatform compatibility guide includes the relevant 2.3.20–2.3.21 range).

If other Android modules (e.g., packages/ndk_flutter/android/build.gradle) still pin Kotlin 2.1.0, align the Kotlin/KGP versions or document why they intentionally differ.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/sample-app/android/build.gradle` at line 2, The Kotlin version
declaration ext.kotlin_version = '2.3.21' must be validated for compatibility
with the Kotlin Gradle Plugin, Gradle, AGP and the JVM toolchain and kept
consistent across Android modules; verify that Kotlin 2.3.21 is the intended
released target, update the Kotlin Gradle plugin dependency and any module-level
Kotlin version pins (e.g., packages/ndk_flutter/android/build.gradle) to the
same compatible version or explicitly document why a different version is
required, and ensure the project Gradle and Android Gradle Plugin versions and
JDK/toolchain meet Kotlin 2.3.21 compatibility before merging.

Comment on lines +46 to +49
// Load the cashu seed phrase from secure storage, generating a fresh one on
// first run. Never hardcode this — it controls cashu funds.
final cashuSeedPhrase = await CashuSeedStore().loadOrCreate();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard seed-store initialization to avoid app boot failure.

Line 48 can throw before runApp, which makes startup fail hard. Add an explicit fallback path (or degrade with cashuUserSeedphrase: null) so the app can still boot.

Suggested fix
-  final cashuSeedPhrase = await CashuSeedStore().loadOrCreate();
+  String? cashuSeedPhrase;
+  try {
+    cashuSeedPhrase = await CashuSeedStore().loadOrCreate();
+  } catch (e, st) {
+    debugPrint('Failed to initialize Cashu seed storage: $e');
+    FlutterError.reportError(
+      FlutterErrorDetails(
+        exception: e,
+        stack: st,
+        context: ErrorDescription('while loading Cashu seed phrase'),
+      ),
+    );
+  }
@@
-      cashuUserSeedphrase: CashuUserSeedphrase(
-        seedPhrase: cashuSeedPhrase,
-      ),
+      cashuUserSeedphrase: cashuSeedPhrase == null
+          ? null
+          : CashuUserSeedphrase(seedPhrase: cashuSeedPhrase),

Also applies to: 57-59

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/sample-app/lib/main.dart` around lines 46 - 49, The Cashu seed
initialization can throw before runApp, so wrap the call to
CashuSeedStore().loadOrCreate() in a try/catch and on error set cashuSeedPhrase
to null (or a safe fallback) instead of letting the exception bubble; ensure the
variable passed to runApp (cashuUserSeedphrase) uses this guarded value. Do the
same guarding for the other initialization site referenced (the lines around the
second loadOrCreate call), and ensure downstream code that consumes
cashuUserSeedphrase tolerates null (degrade behavior) so the app can still boot.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/ndk/lib/domain_layer/usecases/cashu/cashu_backup.dart (1)

173-176: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Reject unsupported older backup versions too.

This guard only rejects versions greater than backupVersion, so 0 or other unhandled older versions still enter the v1 restore path even though there is no migration logic for them. For a versioned backup format, accept only versions you explicitly support.

Suggested fix
     final version = json['version'];
-    if (version is! int || version > backupVersion) {
+    if (version != backupVersion) {
       throw ArgumentError(
-          'Unsupported backup version: $version (this build supports up to $backupVersion)');
+          'Unsupported backup version: $version (expected $backupVersion)');
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ndk/lib/domain_layer/usecases/cashu/cashu_backup.dart` around lines
173 - 176, The current guard only rejects versions greater than backupVersion
but allows older unsupported versions; change the check in the Cashu backup JSON
parsing (the variables `version` and `backupVersion`) to accept only explicitly
supported versions (e.g., require `version == backupVersion` or membership in a
supportedVersions set) and throw an ArgumentError for any other value (including
older ones), updating the error message to reflect unsupported version values.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/ndk/lib/domain_layer/usecases/cashu/cashu_backup.dart`:
- Around line 216-217: The code currently defaults a missing/nullable proof
state to 'UNSPENT' when calling CashuProofState.fromValue(map['state'] as
String? ?? 'UNSPENT'); change this so a missing or null map['state'] does not
get silently treated as UNSPENT: remove the fallback and explicitly reject or
throw for null/unknown states (e.g., check map['state'] as String? and if
null/invalid throw a descriptive exception or return a failure) so
malformed/legacy payloads are refused; ensure callers such as
Cashu.importBackup*() handle the new error path or provide an explicit migration
before accepting missing state.

---

Outside diff comments:
In `@packages/ndk/lib/domain_layer/usecases/cashu/cashu_backup.dart`:
- Around line 173-176: The current guard only rejects versions greater than
backupVersion but allows older unsupported versions; change the check in the
Cashu backup JSON parsing (the variables `version` and `backupVersion`) to
accept only explicitly supported versions (e.g., require `version ==
backupVersion` or membership in a supportedVersions set) and throw an
ArgumentError for any other value (including older ones), updating the error
message to reflect unsupported version values.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 80450a46-52f1-4e95-ba52-02052b14b82a

📥 Commits

Reviewing files that changed from the base of the PR and between a105f59 and 564c1a5.

📒 Files selected for processing (3)
  • packages/ndk/lib/domain_layer/usecases/cashu/cashu.dart
  • packages/ndk/lib/domain_layer/usecases/cashu/cashu_backup.dart
  • packages/ndk/test/cashu/cashu_backup_test.dart
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/ndk/lib/domain_layer/usecases/cashu/cashu.dart
  • packages/ndk/test/cashu/cashu_backup_test.dart

Comment on lines +216 to +217
state:
CashuProofState.fromValue(map['state'] as String? ?? 'UNSPENT'),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Do not default a missing proof state to UNSPENT.

The exporter always writes state, so this fallback only affects malformed or legacy payloads. Treating an unknown proof lifecycle as UNSPENT can inflate restored balances, and Cashu.importBackup*() refreshes balances immediately after restore, so the bad state becomes user-visible right away. Reject missing state unless you add an explicit migration path. Based on downstream balance refresh behavior in packages/ndk/lib/domain_layer/usecases/cashu/cashu.dart:128-161.

Suggested fix
-          state:
-              CashuProofState.fromValue(map['state'] as String? ?? 'UNSPENT'),
+          state: CashuProofState.fromValue(
+            map['state'] as String? ??
+                (throw ArgumentError('Proof state is required')),
+          ),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ndk/lib/domain_layer/usecases/cashu/cashu_backup.dart` around lines
216 - 217, The code currently defaults a missing/nullable proof state to
'UNSPENT' when calling CashuProofState.fromValue(map['state'] as String? ??
'UNSPENT'); change this so a missing or null map['state'] does not get silently
treated as UNSPENT: remove the fallback and explicitly reject or throw for
null/unknown states (e.g., check map['state'] as String? and if null/invalid
throw a descriptive exception or return a failure) so malformed/legacy payloads
are refused; ensure callers such as Cashu.importBackup*() handle the new error
path or provide an explicit migration before accepting missing state.

@codecov

codecov Bot commented Jun 9, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 61.01695% with 115 lines in your changes missing coverage. Please review.
✅ Project coverage is 72.07%. Comparing base (2452e67) to head (b979d74).

Files with missing lines Patch % Lines
...ib/data_layer/models/wallet_transaction_model.dart 48.99% 76 Missing ⚠️
...ges/ndk/lib/domain_layer/usecases/cashu/cashu.dart 14.81% 23 Missing ⚠️
...main_layer/usecases/cashu/cashu_export_import.dart 90.38% 10 Missing ⚠️
...in_layer/usecases/cashu/cashu_cache_decorator.dart 60.00% 6 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #653      +/-   ##
==========================================
+ Coverage   71.94%   72.07%   +0.12%     
==========================================
  Files         210      212       +2     
  Lines       10698    10993     +295     
==========================================
+ Hits         7697     7923     +226     
- Misses       3001     3070      +69     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@1-leo 1-leo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • going through it a second time

}

class _NCashuSeedBackupWarningState extends State<NCashuSeedBackupWarning> {
late final CashuSeedStore _seedStore = widget.seedStore ?? CashuSeedStore();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure about this default.
Could be pron to mistakes by implicit init.
Wdyt?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think its better to move this up the chain so its easier to spot for the dev and we can keep the implicit seed ux

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
packages/ndk/lib/domain_layer/usecases/cashu/cashu_cache_decorator.dart (1)

168-178: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

setDerivationCounter bypasses mutex synchronization.

The newly added setCashuSecretCounter (lines 110-123) correctly wraps the delegate call in _mutex.synchronized, but the existing setDerivationCounter calls _delegate.setCashuSecretCounter directly without synchronization. This inconsistency could cause race conditions if both methods are used concurrently.

Suggested fix
   Future<void> setDerivationCounter({
     required String keysetId,
     required String mintUrl,
     required int counter,
   }) async {
-    await _delegate.setCashuSecretCounter(
-      mintUrl: mintUrl,
-      keysetId: keysetId,
-      counter: counter,
-    );
+    await _mutex.synchronized(() async {
+      await _delegate.setCashuSecretCounter(
+        mintUrl: mintUrl,
+        keysetId: keysetId,
+        counter: counter,
+      );
+    });
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ndk/lib/domain_layer/usecases/cashu/cashu_cache_decorator.dart`
around lines 168 - 178, The setDerivationCounter method currently calls
_delegate.setCashuSecretCounter directly and bypasses the mutex; wrap the
delegate call inside _mutex.synchronized (same pattern used in
setCashuSecretCounter) to ensure serialized access. Inside setDerivationCounter,
call _mutex.synchronized(() async { await
_delegate.setCashuSecretCounter(mintUrl: mintUrl, keysetId: keysetId, counter:
counter); }); keeping the same parameter mapping and error propagation.
packages/ndk_flutter/lib/l10n/app_zh.arb (1)

1-377: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Missing ARB keys for backup/restore functionality.

The Chinese ARB file is missing the same backup/restore dialog keys as the Russian locale: backup, restore, cashuBackupTitle, cashuBackupWarning, generatingBackup, copyBackup, backupCopiedToClipboard, cashuRestoreTitle, backupJson, backupJsonHint, pleaseEnterBackup, restoringBackup, and restoreSuccess. These keys must be added with Chinese translations to prevent English fallback text in the generated localization code.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ndk_flutter/lib/l10n/app_zh.arb` around lines 1 - 377, The Chinese
ARB is missing several Cashu backup/restore localization keys which causes
English fallbacks; add the following keys with Chinese translations into
app_zh.arb: backup, restore, cashuBackupTitle, cashuBackupWarning,
generatingBackup, copyBackup, backupCopiedToClipboard, cashuRestoreTitle,
backupJson, backupJsonHint, pleaseEnterBackup, restoringBackup, and
restoreSuccess (use the same key names as in the Russian locale and provide
appropriate Chinese strings for each) so the generated localization includes
Chinese variants for the backup/restore dialog.
packages/ndk_flutter/lib/l10n/app_ru.arb (1)

1-377: ⚠️ Potential issue | 🟠 Major

Add missing ARB entries for Cashu backup/restore dialog strings (avoid English fallback)

  • packages/ndk_flutter/lib/l10n/app_ru.arb is missing keys backup, restore, cashuBackupTitle, cashuBackupWarning, generatingBackup, copyBackup, backupCopiedToClipboard, cashuRestoreTitle, backupJson, backupJsonHint, pleaseEnterBackup, restoringBackup, restoreSuccess.
  • packages/ndk_flutter/lib/l10n/app_localizations_ru.dart still defines these getters, but their values are English (e.g., cashuBackupTitle/generatingBackup/copyBackup/backupCopiedToClipboard/cashuRestoreTitle), so the Russian UI will show English in the backup/restore flow.
  • The same missing key set shows up across other non-en packages/ndk_flutter/lib/l10n/app_*.arb files (only app_en.arb contains them).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ndk_flutter/lib/l10n/app_ru.arb` around lines 1 - 377, The Russian
ARB is missing the Cashu backup/restore localization keys (backup, restore,
cashuBackupTitle, cashuBackupWarning, generatingBackup, copyBackup,
backupCopiedToClipboard, cashuRestoreTitle, backupJson, backupJsonHint,
pleaseEnterBackup, restoringBackup, restoreSuccess) which causes
app_localizations_ru.dart getters to fall back to English; add these keys with
Russian translations into packages/ndk_flutter/lib/l10n/app_ru.arb (matching the
same keys present in app_en.arb) so the getters in app_localizations_ru.dart
return localized Russian strings instead of English.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/ndk_flutter/lib/l10n/app_ru.arb`:
- Around line 1-377: The Russian ARB is missing the Cashu backup/restore
localization keys (backup, restore, cashuBackupTitle, cashuBackupWarning,
generatingBackup, copyBackup, backupCopiedToClipboard, cashuRestoreTitle,
backupJson, backupJsonHint, pleaseEnterBackup, restoringBackup, restoreSuccess)
which causes app_localizations_ru.dart getters to fall back to English; add
these keys with Russian translations into
packages/ndk_flutter/lib/l10n/app_ru.arb (matching the same keys present in
app_en.arb) so the getters in app_localizations_ru.dart return localized Russian
strings instead of English.

In `@packages/ndk_flutter/lib/l10n/app_zh.arb`:
- Around line 1-377: The Chinese ARB is missing several Cashu backup/restore
localization keys which causes English fallbacks; add the following keys with
Chinese translations into app_zh.arb: backup, restore, cashuBackupTitle,
cashuBackupWarning, generatingBackup, copyBackup, backupCopiedToClipboard,
cashuRestoreTitle, backupJson, backupJsonHint, pleaseEnterBackup,
restoringBackup, and restoreSuccess (use the same key names as in the Russian
locale and provide appropriate Chinese strings for each) so the generated
localization includes Chinese variants for the backup/restore dialog.

In `@packages/ndk/lib/domain_layer/usecases/cashu/cashu_cache_decorator.dart`:
- Around line 168-178: The setDerivationCounter method currently calls
_delegate.setCashuSecretCounter directly and bypasses the mutex; wrap the
delegate call inside _mutex.synchronized (same pattern used in
setCashuSecretCounter) to ensure serialized access. Inside setDerivationCounter,
call _mutex.synchronized(() async { await
_delegate.setCashuSecretCounter(mintUrl: mintUrl, keysetId: keysetId, counter:
counter); }); keeping the same parameter mapping and error propagation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f23aa9e7-04e7-49f5-a145-2816ac3768f3

📥 Commits

Reviewing files that changed from the base of the PR and between 564c1a5 and a2dda5b.

📒 Files selected for processing (31)
  • packages/ndk/lib/data_layer/models/wallet_transaction_model.dart
  • packages/ndk/lib/domain_layer/usecases/cashu/cashu.dart
  • packages/ndk/lib/domain_layer/usecases/cashu/cashu_cache_decorator.dart
  • packages/ndk/lib/domain_layer/usecases/cashu/cashu_export_import.dart
  • packages/ndk/lib/ndk.dart
  • packages/ndk/test/cashu/cashu_import_export_test.dart
  • packages/ndk_flutter/lib/l10n/app_de.arb
  • packages/ndk_flutter/lib/l10n/app_en.arb
  • packages/ndk_flutter/lib/l10n/app_es.arb
  • packages/ndk_flutter/lib/l10n/app_fi.arb
  • packages/ndk_flutter/lib/l10n/app_fr.arb
  • packages/ndk_flutter/lib/l10n/app_it.arb
  • packages/ndk_flutter/lib/l10n/app_ja.arb
  • packages/ndk_flutter/lib/l10n/app_localizations.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_de.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_en.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_es.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_fi.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_fr.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_it.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_ja.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_pl.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_pt.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_ru.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_zh.dart
  • packages/ndk_flutter/lib/l10n/app_pl.arb
  • packages/ndk_flutter/lib/l10n/app_pt.arb
  • packages/ndk_flutter/lib/l10n/app_pt_BR.arb
  • packages/ndk_flutter/lib/l10n/app_ru.arb
  • packages/ndk_flutter/lib/l10n/app_zh.arb
  • packages/ndk_flutter/lib/widgets/wallets/wallet_action_dialogs.dart
✅ Files skipped from review due to trivial changes (9)
  • packages/ndk/test/cashu/cashu_import_export_test.dart
  • packages/ndk/lib/ndk.dart
  • packages/ndk_flutter/lib/l10n/app_de.arb
  • packages/ndk_flutter/lib/l10n/app_pt.arb
  • packages/ndk_flutter/lib/l10n/app_es.arb
  • packages/ndk_flutter/lib/l10n/app_fr.arb
  • packages/ndk_flutter/lib/l10n/app_en.arb
  • packages/ndk_flutter/lib/l10n/app_it.arb
  • packages/ndk_flutter/lib/l10n/app_localizations_fr.dart
🚧 Files skipped from review as they are similar to previous changes (15)
  • packages/ndk_flutter/lib/l10n/app_fi.arb
  • packages/ndk_flutter/lib/l10n/app_pl.arb
  • packages/ndk_flutter/lib/l10n/app_pt_BR.arb
  • packages/ndk_flutter/lib/l10n/app_ja.arb
  • packages/ndk_flutter/lib/l10n/app_localizations_en.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_it.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_ja.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_zh.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_de.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_fi.dart
  • packages/ndk_flutter/lib/l10n/app_localizations.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_pl.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_es.dart
  • packages/ndk_flutter/lib/l10n/app_localizations_pt.dart
  • packages/ndk_flutter/lib/widgets/wallets/wallet_action_dialogs.dart

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants