Repository navigation
fix(accounts): serialize account-mutating auth actions - #1066
Open
aristidesstaffieri wants to merge 1 commit into
Open
aristidesstaffieri wants to merge 1 commit into
aristidesstaffieri wants to merge 1 commit into
Conversation
Port of stellar/freighter#3086. Sign-up, import, sign-in, add, rename, switch and the wipe's storage clear now run one at a time behind a promise-chain lock. A lazily loaded private key is written to a fresh read of the temporary store under the lock. A switch drops its account if a soft-lock lands mid-switch. Funded-account lookups during a recovery-phrase import time out after 5s.
Contributor
|
iOS Simulator preview build is ready: https://github.com/stellar/freighter-mobile/releases/tag/untagged-d421891485493c1638d2 |
14 of 25 tasks
Contributor
|
Android Emulator preview APK is ready: https://github.com/stellar/freighter-mobile/releases/tag/untagged-d1a771bcd2a4ff9af07d |
aristidesstaffieri
marked this pull request as ready for review
November 13, 2026 16:52
12 of 23 tasks
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.
Closes stellar/freighter-private#112
What
Ports stellar/freighter#3086 to mobile. The auth store actions that change accounts, sources or the session now run one at a time behind a promise-chain lock (
helpers/accountMutationLock.ts). That covers sign-up, phrase import, sign-in, create account, add recovery phrase, secret key import, rename, account switch, and the storage-clearing part of a wipe. Each action holds the lock only around its module function inducks/auth.ts, and the reads that follow (fetchActiveAccount,getAllAccounts) run after it releases. The lock is not reentrant, so it is never taken inside a holder.Mobile has no background message listener, so the lock sits at the store action instead. The plain lock path of
logoutandsoftLockstay off the lock, so locking the app never waits on a Scrypt import. The wipe waits only for its storage clears. The WalletConnect and WebView cleanup before them makes network calls and holds no account state, so it runs outside.Suggested reading order:
helpers/accountMutationLock.ts, then the store actions at the bottom ofducks/auth.ts, thencachePrivateKeyandwithFundedLookupTimeout.helpers/accountMutationLock.ts(new):withAccountMutationLockruns its callback once every earlier holder has settled. A rejection releases the lock and still reaches the caller.signUp,importWallet,signIn,createAccount,addRecoveryPhraseSource,importSecretKey,renameAccount,selectAccount: each wraps its module call in the lock.signInalso clears the persisted LOCKED marker inside it.logout(true): the storage clears, auto-lock reset and biometrics clear run under the lock, so an add, import or switch in flight finishes first and never writes its account back into the wiped wallet.verifyAndCreateExistingAccountsOnNetwork: each Horizon lookup during a phrase import resolves to unfunded after 5s, so a stalled request can't hold the lock and block a wipe.loadAccounttakes no abort signal, so only the wait ends.cachePrivateKey(new): whengetActiveAccountlazily loads a missing private key, it now writes it under the lock onto a fresh read of the temporary store. Before, it wrote back the copy it read first, which could drop a key or phrase that an add saved in between.selectAccount: drops the loaded account if a soft-lock landed during the switch, assignInalready does, so the private key never goes back into a locked store.Not ported from #3086: the subscription removal (mobile never had
subscribeAccount), the active-key mismatch exemptions and sign-out refusal handling (one surface, andlogoutnever refuses), and the auto-lock alarm waiting on the lock (softLockstays immediate).Why
Each of these actions reads the account list, derivation indices, source records and encrypted temporary store, then writes them back whole. Two of them overlapping (a double tap on Add account, a load caching a key while an add finishes, a wipe while an import is still storing) let the later write drop the earlier one's account, name, index or phrase, gave two adds on one phrase the same index, or left an account in a wallet that had just been wiped.
Known limitations
Screenshots / video
N/A, no UI change.
Test plan
accountMutationLock.test.tscovers a second holder waiting for the first, and a rejected holder releasing the lock and passing its error on.auth.test.tscovers two overlapping adds on one phrase taking indices 1 and 2, a wipe during an add leaving no account list or indices behind, a soft-lock during a switch leaving no account in the store, the lazy key cache keeping a key another add wrote since the first read, and a stalled funded lookup cut off at 5s so the import finishes.auth.test.tscase fails with its fix removed.yarn test(5527 passed, 14 skipped) andtsc --noEmitpass.Checklist
PR structure
Testing
Release