Skip to content

feat(accounts): import an additional recovery phrase without wiping the wallet - #3084

Draft
aristidesstaffieri wants to merge 5 commits into
fix/serialize-account-mutationsfrom
feature/import-additional-recovery-phrase
Draft

aristidesstaffieri wants to merge 5 commits into
fix/serialize-account-mutationsfrom
feature/import-additional-recovery-phrase

Conversation

@aristidesstaffieri

@aristidesstaffieri aristidesstaffieri commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

What

Adds "Import Recovery Phrase" to the Add wallet chooser, so someone who already has a wallet can bring in another recovery phrase. The phrase gets its own group in the account switcher with index 0 plus any funded accounts among the first 50 indices on mainnet, and nothing already in the wallet changes. A phrase the wallet already holds, or one whose accounts are already in it, is refused before anything is written. The password check and the funded-account lookup move into shared helpers, which adding a generated phrase and onboarding recovery now also use, so onboarding recovery's lookups run in parallel too. The Paste button from the design is left out because extension pages can't read the clipboard without the clipboardRead permission; a keyboard paste works and clears the clipboard afterwards.

Why

The only way to import a phrase today is onboarding recovery, which deletes every account and source before storing the new phrase, so using it to add a second phrase would wipe the first wallet. Onboarding recovery keeps that behavior because it is also the forgot-password path.

Closes stellar/freighter-private#55

Screenshots / video

Before After

Checklist

  • I have read CONTRIBUTING.md and this PR meets its requirements.
  • This PR has narrow scope and does not mix refactoring with feature changes.
  • This PR adds tests for the new functionality or fixes.
  • These changes have been tested in both Chrome and Firefox.
  • This PR includes relevant before and after screenshots for UI changes.
  • I took the time to review my own PR.

@aristidesstaffieri aristidesstaffieri changed the title feat(accounts): import an additional recovery phrase without wiping t… feat(accounts): import an additional recovery phrase without wiping the wallet Nov 11, 2026
@aristidesstaffieri aristidesstaffieri self-assigned this Nov 11, 2026
@aristidesstaffieri
aristidesstaffieri requested a balanced review from Copilot November 11, 2026 18:43
@github-actions

github-actions Bot commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

PR Preview build is ready: https://github.com/stellar/freighter/releases/tag/untagged-5678b1b39ce5bced5e96
Backend: sandbox (aristidesstaffieri). SDF collaborators only — install instructions in the release description.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Overlapping imports can create duplicate keystores and race account-list updates, while a failed first account write can leave the recovery phrase registered and block retries.

3 open issues
What changed in this PR

Adds an additional recovery-phrase import flow to Freighter’s existing wallet, separate from the destructive onboarding recovery flow.

Changes:

  • Adds phrase entry, password confirmation, navigation, translations, and screen metrics.
  • Introduces a background import handler with duplicate checks and mainnet discovery across the first 50 derivation indices.
  • Shares password verification and parallel account discovery helpers, with unit and end-to-end coverage.
File Description
extension/​src/​popup/​views/​ImportRecoveryPhrase/​styles.scss Styles the phrase-entry form.
extension/​src/​popup/​views/​ImportRecoveryPhrase/​index.tsx Adds phrase validation and password-confirmed import.
extension/​src/​popup/​views/​AddWallet/​index.tsx Adds the recovery-phrase import option.
extension/​src/​popup/​views/​__tests__/​ImportRecoveryPhrase.test.tsx Tests import interactions, errors, and clipboard handling.
extension/​src/​popup/​views/​__tests__/​CreateWallet.test.tsx Updates expected chooser options.
extension/​src/​popup/​Router.tsx Registers the import view.
extension/​src/​popup/​metrics/​views.ts Adds import-screen tracking.
extension/​src/​popup/​locales/​pt/​translation.json Adds Portuguese import copy.
extension/​src/​popup/​locales/​en/​translation.json Adds English import copy.
extension/​src/​popup/​ducks/​accountServices.ts Adds the import thunk and result handling.
extension/​src/​popup/​constants/​routes.ts Defines the import route.
extension/​src/​popup/​components/​EnterPassword/​index.tsx Supports custom error formatting.
extension/​src/​background/​messageListener/​popupMessageListener.ts Dispatches imports with discovery depth 50.
extension/​src/​background/​messageListener/​helpers/​verify-add-password.ts Extracts shared password verification.
extension/​src/​background/​messageListener/​helpers/​discover-funded-indices.ts Adds bounded parallel discovery with timeouts.
extension/​src/​background/​messageListener/​handlers/​recoverAccount.ts Reuses discovery for onboarding recovery.
extension/​src/​background/​messageListener/​handlers/​importRecoveryPhrase.ts Adds phrase-source import and account persistence.
extension/​src/​background/​messageListener/​handlers/​addRecoveryPhraseSource.ts Reuses shared password verification.
extension/​src/​background/​messageListener/​__tests__/​verifyAddPassword.test.ts Tests password checks across wallet states.
extension/​src/​background/​messageListener/​__tests__/​importRecoveryPhrase.test.ts Tests discovery, preservation, refusals, and failures.
extension/​src/​background/​messageListener/​__tests__/​discoverFundedIndices.test.ts Tests discovery ordering, concurrency, and timeouts.
extension/​e2e-tests/​helpers/​addWallet.ts Adds a reusable phrase-import interaction helper.
extension/​e2e-tests/​addWallet.test.ts Covers additional imports and duplicate refusal.
@shared/​constants/​services.ts Adds the import service identifier.
@shared/​api/​types/​message-request.ts Defines the typed import request.
@shared/​api/​internal.ts Adds the popup-to-background import API.
@shared/​api/​helpers/​mnemonic.ts Adds normalization and mnemonic validation.
@shared/​api/​helpers/​__tests__/​mnemonic.test.ts Tests accepted and rejected phrase formats.

Review effort: Balanced

@aristidesstaffieri
aristidesstaffieri force-pushed the feature/import-additional-recovery-phrase branch from 2ffe579 to db5ff56 Compare November 11, 2026 21:14
@aristidesstaffieri
aristidesstaffieri changed the base branch from feature/add-wallet-chooser to fix/serialize-account-mutations November 11, 2026 21:15
…he wallet

  Add Import Recovery Phrase to the Add wallet chooser. The new
  importRecoveryPhrase handler validates the phrase, checks the password,
  refuses a phrase or account the wallet already holds, adds index 0 plus
  any funded indices up to 49, and makes index 0 active. Every refusal
  returns before anything is written.

  Move the password check and funded-index discovery into shared helpers.
  addRecoveryPhraseSource and recoverAccount now use them.
@aristidesstaffieri
aristidesstaffieri force-pushed the feature/import-additional-recovery-phrase branch from db5ff56 to 387dadf Compare November 11, 2026 21:30
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