Skip to content

fix: restoreWithMnemonic returns per-unit balances instead of single BigInt - #123

Open
Delgado74 wants to merge 10 commits into
Forte11Cuba:mainfrom
Delgado74:fix/restoreWithMnemonic-per-unit-balances
Open

fix: restoreWithMnemonic returns per-unit balances instead of single BigInt#123
Delgado74 wants to merge 10 commits into
Forte11Cuba:mainfrom
Delgado74:fix/restoreWithMnemonic-per-unit-balances

Conversation

@Delgado74

@Delgado74 Delgado74 commented Apr 22, 2026

Copy link
Copy Markdown

Summary

  • Change restoreWithMnemonic() return type from BigInt to Map<String, BigInt> to preserve unit information
  • Update RecoverTokensModal to display each unit separately (e.g., "1000 sat, 5 USD, 10 EUR")
  • Fix widget_test.dart to use ElCajuApp instead of MyApp

Problem

restoreWithMnemonic() was returning a single BigInt, losing unit information. This caused incorrect display when tokens were recovered from mints with different units (sat, USD, EUR).
Example: Recovering 1000 sat + 5 USD would display as "1005 sat" or "1005 USD" depending on active unit.

Solution

Now returns Map<String, BigInt> (unit → balance), consistent with other restore methods:

  • restoreFromMint()Map<String, BigInt>
  • restoreAllMints()Map<String, Map<String, BigInt>>
  • restoreWithMnemonic()Map<String, BigInt>

Files Changed

  • lib/providers/wallet_provider.dart - Change return type and accumulator
  • lib/screens/8_settings/recover_tokens_modal.dart - Update display logic
  • test/widget_test.dart - Fix class name

Testing

Summary by CodeRabbit

  • Improvements
    • Token recovery now returns and displays recovered balances grouped by mint and unit, with recovery details compiled from units that have positive amounts.
    • The success screen now shows a more precise recovered-tokens message, including which units were found per mint.
  • Tests
    • Updated the widget test to mount the current app root widget while preserving the same counter behavior.
  • Chores
    • Added a manual release workflow to build and upload split-ABI APKs for multiple Android architectures.

…BigInt

- Change restoreWithMnemonic() return type from BigInt to Map<String, BigInt>
- Update RecoverTokensModal to display each unit separately
- Fix widget_test.dart to use ElCajuApp instead of MyApp

Resolves issue Forte11Cuba#104
@coderabbitai

coderabbitai Bot commented Apr 22, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@Delgado74, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 35 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

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.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d66e1936-e559-44ca-85bd-d731f8ac1ea6

📥 Commits

Reviewing files that changed from the base of the PR and between 9a34a04 and 3be59ba.

⛔ Files ignored due to path filters (1)
  • pubspec.lock is excluded by !**/*.lock
📒 Files selected for processing (32)
  • .github/workflows/build-apk.yml
  • .gitignore
  • lib/screens/10_scanner/scan_screen.dart
  • lib/screens/11_payment_request/payment_request_screen.dart
  • lib/screens/12_request/request_screen.dart
  • lib/screens/13_swap/swap_screen.dart
  • lib/screens/2_onboarding/backup_seed_screen.dart
  • lib/screens/2_onboarding/create_wallet_screen.dart
  • lib/screens/2_onboarding/restore_wallet_screen.dart
  • lib/screens/2_onboarding/welcome_screen.dart
  • lib/screens/3_home/home_screen.dart
  • lib/screens/4_receive/receive_screen.dart
  • lib/screens/5_send/offline_send_screen.dart
  • lib/screens/5_send/send_screen.dart
  • lib/screens/5_send/share_token_screen.dart
  • lib/screens/6_mint/invoice_screen.dart
  • lib/screens/6_mint/mint_screen.dart
  • lib/screens/7_melt/amount_screen.dart
  • lib/screens/7_melt/melt_screen.dart
  • lib/screens/8_settings/delete_wallet_modal.dart
  • lib/screens/8_settings/language_screen.dart
  • lib/screens/8_settings/mint_detail_screen.dart
  • lib/screens/8_settings/mints_screen.dart
  • lib/screens/8_settings/p2pk_keys_screen.dart
  • lib/screens/8_settings/pin_dialog.dart
  • lib/screens/8_settings/privacy_screen.dart
  • lib/screens/8_settings/recover_tokens_modal.dart
  • lib/screens/8_settings/settings_screen.dart
  • lib/screens/9_history/history_screen.dart
  • lib/widgets/common/numpad_widget.dart
  • lib/widgets/scanner/qr_scanner_widget.dart
  • pubspec.yaml
📝 Walkthrough

Walkthrough

Mnemonic recovery now returns balances grouped by mint and unit, with corresponding per-unit UI formatting. The widget test uses ElCajuApp, and a manual workflow builds release APKs for three Android architectures.

Changes

Wallet Recovery

Layer / File(s) Summary
Per-mint/unit recovery results
lib/providers/wallet_provider.dart, lib/screens/8_settings/recover_tokens_modal.dart
Recovery returns nested mint/unit balances, which the modal aggregates and formats for successful recoveries.
Widget test root
test/widget_test.dart
The widget test now pumps ElCajuApp instead of MyApp.

APK Release Workflow

Layer / File(s) Summary
Architecture-specific release builds
.github/workflows/build-apk.yml
A manual workflow configures Java, Flutter, Rust, Android NDK, dependencies, and localization generation before building and uploading ARM64, ARMv7, and x86_64 release APKs.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The implementation returns a nested mintUrl/unit map, which does not match #104's requested unit-to-balance return shape. Change restoreWithMnemonic to return the unit-keyed balance map requested in #104 and update RecoverTokensModal to consume that same shape.
Out of Scope Changes check ⚠️ Warning The added APK build workflow is unrelated to #104's restore and recovery UI changes. Remove the GitHub Actions APK workflow from this PR or split it into a separate CI-focused change.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change to restoreWithMnemonic's return value.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@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)
test/widget_test.dart (1)

16-28: ⚠️ Potential issue | 🟠 Major

Wrap ElCajuApp with providers and replace stale counter assertions.

ElCajuApp calls context.watch<SettingsProvider>() and context.read<WalletProvider>(), which require ancestor providers. The test will fail during initialization with a ProviderNotFoundException. Additionally, ElCajuApp routes to SplashScreen (showing a loading screen), not the Flutter counter sample, so the counter assertions (expect(find.text('0')..., find.byIcon(Icons.add)) are stale and will fail.

Wrap ElCajuApp in MultiProvider with all four providers (SettingsProvider, WalletProvider, P2PKProvider, PriceProvider), and replace the counter assertions with expectations that match what SplashScreen actually renders (e.g., find.byType(CircularProgressIndicator) or logo/text queries). Add imports for MultiProvider, ChangeNotifierProvider, and the specific provider classes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/widget_test.dart` around lines 16 - 28, The test fails because ElCajuApp
reads SettingsProvider and WalletProvider and routes to SplashScreen rather than
the Flutter counter sample; wrap the app in a MultiProvider that supplies
ChangeNotifierProvider instances for SettingsProvider, WalletProvider,
P2PKProvider and PriceProvider (ensure you add imports for MultiProvider and
ChangeNotifierProvider and the provider classes), then replace the stale
counter-based expectations and the tap on Icons.add with assertions that match
SplashScreen output (e.g., expect(find.byType(CircularProgressIndicator),
findsOneWidget) or queries for the app logo/text rendered by SplashScreen) so
the test initializes with the required providers and asserts the actual initial
UI.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/screens/8_settings/recover_tokens_modal.dart`:
- Around line 687-688: The call to l10n.recoveredTokens currently passes
recoveredDetails.length (count of unit buckets) which is incorrect; change the
second argument to the count of distinct mints (use recoveredMap.keys.length or
mintsRecovered) so l10n.recoveredTokens(recoveredDetails.join(", "),
recoveredMap.keys.length) (or use mintsRecovered) reports mint count rather than
unit bucket count.

---

Outside diff comments:
In `@test/widget_test.dart`:
- Around line 16-28: The test fails because ElCajuApp reads SettingsProvider and
WalletProvider and routes to SplashScreen rather than the Flutter counter
sample; wrap the app in a MultiProvider that supplies ChangeNotifierProvider
instances for SettingsProvider, WalletProvider, P2PKProvider and PriceProvider
(ensure you add imports for MultiProvider and ChangeNotifierProvider and the
provider classes), then replace the stale counter-based expectations and the tap
on Icons.add with assertions that match SplashScreen output (e.g.,
expect(find.byType(CircularProgressIndicator), findsOneWidget) or queries for
the app logo/text rendered by SplashScreen) so the test initializes with the
required providers and asserts the actual initial UI.
🪄 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: 0f0bab7a-64e7-4667-ab69-44f855d315ae

📥 Commits

Reviewing files that changed from the base of the PR and between 7ec4e4e and 9e832bd.

📒 Files selected for processing (3)
  • lib/providers/wallet_provider.dart
  • lib/screens/8_settings/recover_tokens_modal.dart
  • test/widget_test.dart

Comment thread lib/screens/8_settings/recover_tokens_modal.dart Outdated
- Change return type to Map<String, Map<String, BigInt>> (mintUrl -> unit -> balance)
- Count mints with tokens > 0 instead of unit count
- Now shows correct mint count (e.g., '2 mints' not '5 units')

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/providers/wallet_provider.dart`:
- Around line 1995-2008: Before calling ourWallet.receive(...), persist the
transfer token so it can be retried if receive() throws: after
tempWallet.send(...) succeeds, call a helper like
persistPendingToken(result.token, mintUrl, unit) (or equivalent persistence
mechanism) immediately, then call ourWallet.receive(token: result.token); on
successful receive remove the persisted token via deletePendingToken(mintUrl,
unit, result.token) and update results as you already do; if receive throws, do
not delete the persisted token so it remains retryable and ensure any exception
handling/logging does not lose the token information. Use the existing symbols
tempWallet.prepareSend, tempWallet.send, ourWallet.receive and results to locate
where to add persistence and cleanup.
🪄 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: d3646e61-4e48-4b32-86f2-b9acdfae0401

📥 Commits

Reviewing files that changed from the base of the PR and between 9e832bd and 3317b92.

📒 Files selected for processing (2)
  • lib/providers/wallet_provider.dart
  • lib/screens/8_settings/recover_tokens_modal.dart
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/screens/8_settings/recover_tokens_modal.dart

Comment thread lib/providers/wallet_provider.dart

@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: 2

🧹 Nitpick comments (1)
.github/workflows/build-apk.yml (1)

15-147: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Refactor to use a matrix strategy.

The three build jobs (build-arm64, build-armv7, build-x86-64) share identical steps, differing only in the target architectures and artifact names. Consolidating them into a single matrix job will significantly reduce code duplication and simplify future maintenance.

♻️ Proposed refactor using a matrix strategy
jobs:
  build-apk:
    name: Build ${{ matrix.name }}
    runs-on: ubuntu-latest
    timeout-minutes: 60
    strategy:
      matrix:
        include:
          - name: ARM64 (armV8)
            rust_target: aarch64-linux-android
            flutter_platform: android-arm64
            artifact_name: elcaju-arm64-v8a
            apk_path: app-arm64-v8a-release.apk # Adjust if the actual output is app-release.apk
          - name: ARMv7 (armV7)
            rust_target: armv7-linux-androideabi
            flutter_platform: android-arm
            artifact_name: elcaju-armeabi-v7a
            apk_path: app-armeabi-v7a-release.apk
          - name: x86_64
            rust_target: x86_64-linux-android
            flutter_platform: android-x64
            artifact_name: elcaju-x86-64
            apk_path: app-x86_64-release.apk
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ inputs.branch }}
          persist-credentials: false

      - name: Setup Java 17
        uses: actions/setup-java@v4
        with:
          distribution: 'zulu'
          java-version: '17'

      - name: Setup Flutter
        uses: subosito/flutter-action@v2
        with:
          channel: stable

      - name: Setup Rust toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.rust_target }}

      - name: Install Android NDK
        run: echo "y" | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager "ndk;27.0.12077973"

      - name: Install dependencies
        run: flutter pub get

      - name: Generate localizations
        run: flutter gen-l10n

      - name: Build APK
        run: flutter build apk --release --target-platform ${{ matrix.flutter_platform }}

      - name: Upload APK
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.artifact_name }}
          path: build/app/outputs/flutter-apk/${{ matrix.apk_path }}
🤖 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 @.github/workflows/build-apk.yml around lines 15 - 147, Replace the
duplicated build-arm64, build-armv7, and build-x86-64 jobs with one build-apk
matrix job. Define each architecture’s name, Rust target, Flutter target
platform, artifact name, and APK path under matrix.include, then reuse those
values in the setup, build, and upload steps while preserving the existing
shared workflow behavior.
🤖 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 @.github/workflows/build-apk.yml:
- Around line 22-24: Disable credential persistence for every checkout action in
.github/workflows/build-apk.yml at lines 22-24, 66-68, and 110-112 by adding
persist-credentials: false to each action's with configuration.
- Around line 51-59: Update the ARM64 build and upload steps at
.github/workflows/build-apk.yml lines 51-59, the corresponding site at lines
95-103, and the corresponding site at lines 139-147 so each build generates
split-per-ABI APKs by adding the required Flutter build option, preserving the
existing ABI-specific artifact paths and names.

---

Nitpick comments:
In @.github/workflows/build-apk.yml:
- Around line 15-147: Replace the duplicated build-arm64, build-armv7, and
build-x86-64 jobs with one build-apk matrix job. Define each architecture’s
name, Rust target, Flutter target platform, artifact name, and APK path under
matrix.include, then reuse those values in the setup, build, and upload steps
while preserving the existing shared workflow behavior.
🪄 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: f737f8e0-893f-464b-aac8-ffc3aaa0a2d9

📥 Commits

Reviewing files that changed from the base of the PR and between 3317b92 and f12c48d.

📒 Files selected for processing (1)
  • .github/workflows/build-apk.yml

Comment thread .github/workflows/build-apk.yml Outdated
Comment on lines +22 to +24
- uses: actions/checkout@v4
with:
ref: ${{ inputs.branch }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Disable credential persistence in checkout.

To prevent potential credential leakage through GitHub Actions artifacts, set persist-credentials: false in the checkout action, as flagged by static analysis.

  • .github/workflows/build-apk.yml#L22-L24: Add persist-credentials: false to the checkout action.
  • .github/workflows/build-apk.yml#L66-L68: Add persist-credentials: false to the checkout action.
  • .github/workflows/build-apk.yml#L110-L112: Add persist-credentials: false to the checkout action.
🧰 Tools
🪛 zizmor (1.26.1)

[warning] 22-24: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)

📍 Affects 1 file
  • .github/workflows/build-apk.yml#L22-L24 (this comment)
  • .github/workflows/build-apk.yml#L66-L68
  • .github/workflows/build-apk.yml#L110-L112
🤖 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 @.github/workflows/build-apk.yml around lines 22 - 24, Disable credential
persistence for every checkout action in .github/workflows/build-apk.yml at
lines 22-24, 66-68, and 110-112 by adding persist-credentials: false to each
action's with configuration.

Source: Linters/SAST tools

Comment thread .github/workflows/build-apk.yml Outdated
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.

fix: restoreWithMnemonic should return per-unit balances instead of a single BigInt

1 participant