11<template >
22 <Modal :close =" close " :visible =" visible " >
33 <template v-slot :header >
4- <h2 >Unlock wallet</h2 >
4+ <h2 >{{ migrationFailed ? 'Migration Failed' : ' Unlock wallet' }} </h2 >
55 </template >
66
77 <template v-slot :body >
8- <div class =" pt-15" >
8+ <div v-if =" migrationFailed" class =" pt-15" >
9+ <div class =" flex items-start leading-8 text-gray mb-14" >
10+ <p >Wallet migration to the new format failed. Please copy your private key below and reset your wallet to continue.</p >
11+ </div >
12+ <div class =" form-group" >
13+ <label >wallet address</label >
14+ <span class =" break-all" >{{ address }}</span >
15+ </div >
16+ <div class =" form-group mb-25" >
17+ <label >PRIVATE KEY</label >
18+ <span class =" font-mono break-all text-sm2" >{{ legacyPrivateKey }}</span >
19+ </div >
20+ </div >
21+
22+ <div v-else class =" pt-15" >
923 <form >
1024 <div v-if =" walletVersion < 2" class =" form-group" >
1125 <label >wallet address</label >
3448 </template >
3549
3650 <template v-slot :footer >
37- <div class =" grid grid-cols-1 gap-24 px-24 pt-48 border-gray-700 border-solid md:grid-cols-2 border-t-default border-opacity-30 pb-54" >
51+ <div v-if =" migrationFailed" class =" px-24 pt-48 border-gray-700 border-solid border-t-default border-opacity-30 pb-54" >
52+ <button
53+ class =" w-full border-red-600 button button--outline-success hover:border-red-600 hover:bg-red-600"
54+ @click =" switchToForgetModal"
55+ >
56+ Reset wallet
57+ </button >
58+ </div >
59+ <div v-else class =" grid grid-cols-1 gap-24 px-24 pt-48 border-gray-700 border-solid md:grid-cols-2 border-t-default border-opacity-30 pb-54" >
3860 <button
3961 class =" w-full border-red-600 button button--outline-success hover:border-red-600 hover:bg-red-600"
4062 @click =" switchToForgetModal"
4870</template >
4971
5072<script >
51- import * as xe from ' @edge/xe-utils'
5273import * as storage from ' ../../utils/storage'
5374import * as validation from ' ../../utils/validation'
5475import { LockOpenIcon } from ' @heroicons/vue/outline'
@@ -65,7 +86,9 @@ export default {
6586 data () {
6687 return {
6788 password: ' ' ,
68- passwordError: ' '
89+ passwordError: ' ' ,
90+ migrationFailed: false ,
91+ legacyPrivateKey: ' '
6992 }
7093 },
7194 validations () {
@@ -106,22 +129,48 @@ export default {
106129 if (! await this .v$ .$validate ()) return
107130 if (! await this .checkPassword ()) return
108131
109- // Migrate vault from older versions if needed
110- if (await storage .needsMigration ()) {
111- await storage .migrateToV2 (this .password )
132+ // Attempt migration from older versions
133+ try {
134+ if (await storage .needsMigration ()) {
135+ await storage .migrateToV2 (this .password )
136+ }
137+ }
138+ catch (err) {
139+ // Migration failed — old data preserved (write-verify-delete pattern)
140+ // Show private key so user can export and reset
141+ console .error (' Migration failed:' , err)
142+ this .legacyPrivateKey = await storage .getLegacyPrivateKey (this .password )
143+ if (this .legacyPrivateKey ) {
144+ this .migrationFailed = true
145+ } else {
146+ this .passwordError = ' Migration failed and wallet data could not be read.'
147+ }
148+ return
112149 }
113150
114- const publicKey = await storage .getPublicKey (this .password )
115- const highestVersion = storage .getHighestWalletVersion ()
116- const address = xe .wallet .deriveAddress (publicKey)
117- this .$store .commit (' setAddress' , address)
118- this .$store .commit (' setVersion' , highestVersion)
119- this .$store .commit (' unlock' )
151+ try {
152+ // Use actual stored version (reflects migration success)
153+ this .$store .commit (' setVersion' , await storage .getWalletVersion ())
154+ this .$store .commit (' unlock' )
120155
121- await this . $store . dispatch ( ' loadWallets' , this . password )
122- this .$store .dispatch (' refresh ' )
156+ // loadWallets derives addresses from vault (v2) or state (legacy )
157+ await this .$store .dispatch (' loadWallets ' , this . password )
123158
124- this .afterUnlock ()
159+ // Verify wallet loaded before navigating away
160+ if (! this .$store .state .address ) {
161+ this .$store .commit (' lock' )
162+ this .passwordError = ' Failed to load wallet data. Please try again.'
163+ return
164+ }
165+
166+ this .$store .dispatch (' refresh' )
167+ this .afterUnlock ()
168+ }
169+ catch (err) {
170+ // Roll back unlock state so user stays on unlock screen
171+ this .$store .commit (' lock' )
172+ this .passwordError = err .message || ' An error occurred while unlocking.'
173+ }
125174 },
126175 unlockOnEnter (event ) {
127176 if (event .charCode !== 13 ) return
0 commit comments