joinmarket-webui / joinmarket-webui/jam

Import Wallet flow doesn't guard against post-recovery failures — a downstream error shows "import failed" with no indication the wallet already exists

Open
#1,435 1 comment 0 reactions 1 assignee Claimed by @GuTS805 View on GitHub
bug
Dominant language
TypeScript
Stars
330
Forks
122
Avg merge
2d 17h
Merged PRs (30d)
17

Description

**Expected behavior**

If the wallet has already been recovered successfully on the backend during Import, a failure in some later cleanup step (gaplimit reset, rescan trigger etc) shouldnt just tell the user "import failed" with zero indication that a real wallet now exists.

**Actual behavior**

`src/components/import/ImportWalletPage.tsx:147-286` (`handleConfirm`) runs the whole import as 5 backend calls back to back, all inside one single try block:

1. `recoverWallet.mutateAsync` (164-171) - recovers the wallet on the backend using the users actual seed phrase. once this succeeds, theres a real wallet sitting on the node.
2. `fetchConfig`, then maybe `updateConfig` to bump gaplimit (187-206)
3. `lockWallet` then `unlockWallet` (208-218), token gets replaced after this (220-225)
4. reset gaplimit back if it was changed (227-238)
5. `rescanMutation` (241-246)

none of steps 2 to 5 have their own try/catch. so if any of them throw (network hiccup, backend error, timeout, whatever), it jumps straight to the one outer catch (264-282), which just shows a generic "import failed" toast and tries to lock the wallet on a best effort basis. nothing tells the user that step 1 already worked and their wallet is actually sitting there now.

theres also a second issue from the same gap - if it fails after the gaplimit gets bumped (step 2, line 198) but before its reset back (step 4, line 230), like if lockWallet/unlockWallet throws, then gaplimit stays changed permanently and silently, no mention of it anywhere in the error.

**Steps to reproduce the problem**

1. start Import Wallet with a valid seed phrase, gaplimit different from wallets default
2. let recoverWallet succeed
3. make any of steps 2-5 fail, easiest way is throttling/killing network right after the recover-wallet call finishes (devtools), or force an error on updateConfig/lockWallet/unlockWallet/rescan somehow
4. you get the generic "import failed" toast, no mention a wallet was actually made, no link to it
5. go check the login pages wallet list - wallet is right there, works fine, just nobody told you

**Additional context**

what made me actually file this - the sibling Create Wallet flow already handles this exact problem. `src/components/create/CreateWalletPage.tsx:150-164` wraps its lock step in its own try/catch with a comment saying "user might face some problem afterwards, but can still write down the mnemonic phrase" and they even named the caught error `_ignoredOnPurpose`. so this was clearly a deliberate choice on their end to not let a later failure hide a wallet that already got created. and ImportWalletPage.tsx even does this same thing already for one step (hashPassword, 181-185) - it just never got applied to the other 4 steps that run after the wallet is recovered.

this is "beta software, use with caution" and its the actual seed phrase recovery flow. someone could hit a transient failure in any of 4 backend calls that all happen after their wallet is already fully recovered, and get told it "failed" with nothing saying a wallet with their keys now exists on the node. no obvious way back to it either, so they might just assume it didnt work and give up.

to be clear no funds are lost here, wallet is completely fine and sitting in the login list. but the app is telling the user something thats flat out wrong compared to what actually happened on the backend.

**Proposed fix direction**

same pattern as CreateWalletPage.tsx, and same pattern already used once in this same function for hashPassword - wrap steps 2 through 5 in their own try/catch that logs a warning but doesnt kill the whole flow once step 1 (recoverWallet) has gone through. update the toast copy so it still says the wallet was recovered even if some later step (gaplimit reset, rescan) failed, and point the user toward the wallet list / login page.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.