Skip to content

Fix restore bug: all proofs had same secret; convert to streaming API#413

Merged
1-leo merged 10 commits intocashu-walletfrom
copilot/implement-nut13-nut09-restore
Feb 5, 2026
Merged

Fix restore bug: all proofs had same secret; convert to streaming API#413
1-leo merged 10 commits intocashu-walletfrom
copilot/implement-nut13-nut09-restore

Conversation

Copy link
Contributor

Copilot AI commented Feb 4, 2026

During wallet restoration, all proofs were assigned the same secret and blinding factor. The matching logic used keyset IDs to pair signatures with blinded messages, but all messages in a batch share the same keyset ID, causing firstWhere to always return the first item.

Changes

Fixed signature-to-message matching

  • Parse both outputs and signatures from NUT-09 restore response (was only parsing signatures)
  • Match by index: outputs[i]signatures[i], then lookup blinded message by B_ value
  • Fallback to exhaustive matching if outputs not provided by mint
// Before: always matched the first item
final matchingItem = messageMap.values.firstWhere(
  (item) => item.blindedMessage.id == signature.id,  // All have same keyset ID!
);

// After: match by B_ value from response
final blindedItem = messageMap[output.blindedMessage];  // Unique B_ value

Converted to streaming API

  • Cashu.restore() now returns Stream<CashuRestoreResult> instead of Future
  • Yields progress after each keyset processed
  • Saves proofs and updates balances incrementally
await for (final result in wallet.restore(mintUrl: url, unit: 'sat')) {
  print('${result.totalProofsRestored} proofs restored');
}

Updated test

  • Verifies each restored proof has unique secret
  • Consumes stream and validates progress updates

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • dev.mint.camelus.app
    • Triggering command: /tmp/dart-sdk/bin/dartvm /tmp/dart-sdk/bin/dartvm --resolved_executable_name=/tmp/dart-sdk/bin/dart --executable_name=/tmp/dart-sdk/bin/dart --mark_main_isolate_as_system_isolate .dart_tool/pub/bin/test/test.dart-3.10.9.snapshot test/cashu/cashu_restore_test.dart (dns block)

If you need me to access, download, or install something from one of these locations, you can either:


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 2 commits February 4, 2026 17:28
- Added restore endpoint to CashuRepo interface
- Implemented restore endpoint in CashuRepoImpl
- Created cashu_restore.dart with full restore logic
- Added restore method to Cashu class
- Created comprehensive tests for restore functionality
- Tests verify deterministic secret generation

Co-authored-by: 1-leo <58687994+1-leo@users.noreply.github.com>
Co-authored-by: 1-leo <58687994+1-leo@users.noreply.github.com>
Copilot AI changed the title [WIP] Implement nut13 and nut09 restore methods in Cashu Implement NUT-09 wallet restore with NUT-13 deterministic secrets Feb 4, 2026
Copilot AI requested a review from 1-leo February 4, 2026 17:33
Copilot AI and others added 2 commits February 4, 2026 18:46
- Created comprehensive test that funds wallet1 and restores to wallet2
- Both wallets use the same seed phrase but separate caches
- Test verifies that wallet2 can restore all funds from wallet1
- Test is skipped by default but can be enabled for manual testing with real mint
- Includes detailed logging and step-by-step verification
- Validates that both wallets have identical balances after restore

Co-authored-by: 1-leo <58687994+1-leo@users.noreply.github.com>
Co-authored-by: 1-leo <58687994+1-leo@users.noreply.github.com>
Copilot AI changed the title Implement NUT-09 wallet restore with NUT-13 deterministic secrets Implement proper integration test for Cashu wallet restore Feb 4, 2026
Copilot AI and others added 2 commits February 4, 2026 19:12
The bug was in the matching logic between signatures and blinded messages.
The code was trying to match by keyset ID, but all blinded messages in a
batch share the same keyset ID, so firstWhere always returned the first item.

Solution:
- Updated restore endpoint to parse BOTH outputs and signatures from response
- Match outputs[i] with signatures[i] by index
- Use the B_ value from outputs to find the corresponding blinded message item
- Fallback to trying each combination if outputs aren't provided

This ensures each restored proof gets its correct unique secret and blinding factor.

Co-authored-by: 1-leo <58687994+1-leo@users.noreply.github.com>
As requested, the restore method now returns a Stream instead of a Future.
This allows clients to track progress as proofs are discovered and restored.

Changes:
- Changed Cashu.restore() to return Stream<CashuRestoreResult>
- Changed CashuRestore.restoreAllKeysets() to return Stream<CashuRestoreResult>
- Yields progress updates after each keyset is processed
- Saves proofs incrementally and updates balances as they're discovered
- Updated test to consume stream and show progress
- Added test to verify all proofs have unique secrets (validates the bug fix)

Co-authored-by: 1-leo <58687994+1-leo@users.noreply.github.com>
Copilot AI changed the title Implement proper integration test for Cashu wallet restore Fix restore bug: all proofs had same secret; convert to streaming API Feb 4, 2026
@codecov
Copy link

codecov bot commented Feb 4, 2026

Codecov Report

❌ Patch coverage is 72.78481% with 43 lines in your changes missing coverage. Please review.
✅ Project coverage is 72.31%. Comparing base (0b2f5a2) to head (66f2c09).
⚠️ Report is 1 commits behind head on cashu-wallet.

Files with missing lines Patch % Lines
...lib/domain_layer/usecases/cashu/cashu_restore.dart 66.35% 36 Missing ⚠️
...data_layer/repositories/cashu/cashu_repo_impl.dart 85.00% 3 Missing ⚠️
...ges/ndk/lib/domain_layer/usecases/cashu/cashu.dart 87.50% 3 Missing ⚠️
...in_layer/entities/cashu/cashu_blinded_message.dart 66.66% 1 Missing ⚠️
Additional details and impacted files
@@               Coverage Diff                @@
##           cashu-wallet     #413      +/-   ##
================================================
+ Coverage         72.25%   72.31%   +0.05%     
================================================
  Files               177      179       +2     
  Lines              7612     7769     +157     
================================================
+ Hits               5500     5618     +118     
- Misses             2112     2151      +39     

☔ View full report in Codecov by Sentry.
📢 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 marked this pull request as ready for review February 5, 2026 09:42
@1-leo 1-leo merged commit 7bc9ae5 into cashu-wallet Feb 5, 2026
1 check passed
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