Fix password recovery reminder triggering - #6177
Conversation
📸🪓 Test evidence
recovery reminder on funded account 🪓 HACK-FORCED: rate refresh trigger Captured by the agent's in-app test run (build-and-test). |
a8e87e6 to
4f3fd7c
Compare
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
4872bc3 to
b57b035
Compare
There was a problem hiding this comment.
Claude Code Review
Claude Code Review is paused for this repository. To reconnect it, an admin of this repository's GitHub organization (or the account owner, for personal repositories) who can also manage your Claude organization's Code Review settings needs to re-link GitHub in Code Review settings. This is a one-time step.
Tip: disable this comment in your organization's Code Review settings.
📸🪓 Test evidence (after review fix)
recovery reminder after review fix 🪓 HACK-FORCED: unpriced funded balances diag Captured by the agent's in-app test run (build-and-test). |
b57b035 to
751f47c
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 751f47c. Configure here.
751f47c to
09c01b6
Compare
09c01b6 to
6b0c908
Compare






Description
The password-recovery reminder is meant to fire once per balance milestone ($20 / $200 / $2,000 / $20,000 / $200,000) for accounts with no recovery key. It rarely did, for these reasons:
newTransactions.checkPasswordRecoveryhad exactly one dispatch site, inside thewallet.on('newTransactions')handler. It now also runs on each exchange-rate refresh, so funds that arrived while the app was closed are noticed.getExchangeRatereturns0for a rate it has not loaded, so a partly-loaded rate set undercounts the total and credits the wrong milestone. The thunk now defers while a funded wallet's NATIVE currency has no USD rate, and picks the check back up on a later pass. Only native currencies are checked, and the deferral is bounded to 5 minutes from the account's first check: a token the rates server does not price, or a chain it never prices (a fundedbitcointestnetwallet is a real example on a test account), never gets a rate, so an unbounded wait on one would suppress the reminder for the life of the account. The window is keyed on the account object, not on process start, so it belongs to the login session: sitting on the login screen, or logging into a second account later in the same session, each get their own full window.!transactions[finalTxIndex].isSend, so a batch whose last element was a send skipped the check even when the batch contained receives. It now uses the already-computedreceivedTxs.Trigger paths, before and after
Before, every path to the check was gated on something that was often false:
sequenceDiagram autonumber participant Chain participant Wallet participant ACM as AccountCallbackManager participant Check as checkPasswordRecovery Chain-->>Wallet: deposit lands while the app is closed Note over Wallet,ACM: no listener attached, so no event Wallet-->>ACM: app reopens, wallet syncs ACM--xCheck: never dispatched, the only call site was newTransactions Chain-->>Wallet: deposit while the app is running Wallet->>ACM: newTransactions([receive, send]) ACM--xCheck: skipped, guard read transactions[last].isSend Chain-->>Wallet: deposit on a cold start Wallet->>ACM: newTransactions([receive]) ACM->>Check: dispatch Note over Check: rates not loaded yet, so the total is 0<br/>lt(0, "20") returns early, and nothing re-runs itAfter, the rate-refresh cycle gives the check a second, unconditional entry point, and the two broken guards are fixed:
sequenceDiagram autonumber participant Chain participant Wallet participant ACM as AccountCallbackManager participant Check as checkPasswordRecovery Chain-->>Wallet: deposit lands while the app is closed Wallet-->>ACM: app reopens, wallet syncs loop every rate refresh (30s) ACM->>Check: dispatch alt a funded wallet's native currency has no rate (first 5 min) Note over Check: defer to the next refresh else rates complete Check->>Check: mark every crossed level shown Check-->>ACM: show one reminder modal end end Chain-->>Wallet: deposit while the app is running Wallet->>ACM: newTransactions([receive, send]) ACM->>Check: dispatch, guard is now receivedTxs.length > 0The above also forces two supporting changes:
writePasswordRecoveryReminderstakes a level array so the marks are one read-modify-write, not a race.account.username == null) are skipped. They have no password to recover, and they already get the backup modal from the same handler.Asana: https://app.asana.com/0/1215088146871429/1211152484915503
CHANGELOG
Does this branch warrant an entry to the CHANGELOG?
Dependencies
none
Requirements
If you have made any visual changes to the GUI. Make sure you have:
Note
Medium Risk
Changes when and how often a user-facing security modal appears and ties logic to exchange-rate timing; scope is localized but affects all funded accounts without recovery.
Overview
Fixes the password recovery reminder so it reliably appears at each USD balance milestone ($20–$200k) when the account has no recovery key.
checkPasswordRecoverynow runs after exchange-rate refreshes as well as on incoming receives, so balances that changed while the app was closed are evaluated once rates load. It waits up to five minutes per login for USD rates on funded wallets’ native currencies (tokens/chains the server never prices don’t block forever), skips light accounts, marks all newly crossed milestones in one write, and shows one modal.AccountCallbackManagertriggers the check on any receive in anewTransactionsbatch (not only the last tx) and again afterupdateExchangeRates.writePasswordRecoveryRemindersaccepts multiple levels. Adds unit tests.Reviewed by Cursor Bugbot for commit 09c01b6. Bugbot is set up for automated code reviews on this repo. Configure here.