fix(wallet): close last QA-20 hole — strict marker read in exists()#103
Merged
epicexcelsior merged 1 commit intoJun 13, 2026
Merged
Conversation
QA-20's fix (88bfd5e) stopped hasLocalWallet()/createLocal() deleting on a keychain read error, but both gate on LocalWallet.exists(), whose marker read still used the error-swallowing secureGet. A transient keystore outage (device just unlocked, cross-process lock) read as 'no wallet': cold start routed to onboarding, and tapping create would overwrite the stored secret of a real, funded wallet. - exists() reads the marker with secureGetStrict and throws on read failure - hasLocalWallet() treats a failed marker read as 'wallet present' so the unlock path surfaces a retryable error instead of routing to create - createLocal() refuses to create when existence can't be verified — nothing is written over unknown state - connect() distinguishes a failed pubkey read (retryable, keys intact) from verified absence — 'recreate your wallet' was exactly the wrong advice during a transient outage
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Closes the residual QA-20 funds-safety hole. A transient Keystore read failure could make
LocalWallet.exists()return false, letting the create path overwrite a funded wallet's secret.exists()now reads the wallet marker viasecureGetStrict(throws on read failure) instead of the swallow-to-nullsecureGet, so a transient outage surfaces as an error rather than a false "absent".WalletFactory.hasLocalWallettreats unknown-presence as present and routes to connect (never create);createLocalre-throws without writing. The solecreate()path now requires a verified-absent wallet.Scope
2 files:
LocalWallet.ts,WalletFactory.ts(+44/-5).secureGetStrictalready on staging.Test
tsc clean · tier0 config/services clean · fake-money + lint clean. Code-path fix; invisible until the day it stops an overwrite of a funded wallet.