4
4
5
5
module Pos.Wallet.Web.Methods.Restore
6
6
( newWallet
7
+ , newWalletNoThrow
7
8
, importWallet
8
9
, restoreWalletFromSeed
10
+ , restoreWalletFromSeedNoThrow
9
11
, restoreWalletFromBackup
10
12
, addInitialRichAccount
11
13
@@ -21,6 +23,7 @@ import Data.Default (Default (def))
21
23
import Formatting (build , sformat , (%) )
22
24
import System.IO.Error (isDoesNotExistError )
23
25
import System.Wlog (logDebug )
26
+ import Data.Traversable (for )
24
27
25
28
import qualified Data.HashMap.Strict as HM
26
29
import Pos.Client.KeyStorage (addSecretKey )
@@ -58,47 +61,95 @@ import UnliftIO (MonadUnliftIO)
58
61
initialAccAddrIdxs :: Word32
59
62
initialAccAddrIdxs = firstHardened
60
63
64
+ mnemonicExists :: Text
65
+ mnemonicExists = " Wallet with that mnemonics already exists"
66
+
67
+ -- | Creates a wallet. If the wallet with the given passphrase already exists,
68
+ -- then we return 'Left' of the wallet's ID.
61
69
mkWallet
62
70
:: L. MonadWalletLogic ctx m
63
- => PassPhrase -> CWalletInit -> Bool -> m (EncryptedSecretKey , CId Wal )
71
+ => PassPhrase
72
+ -> CWalletInit
73
+ -> Bool
74
+ -> m (Either (CId Wal ) (EncryptedSecretKey , CId Wal ))
64
75
mkWallet passphrase CWalletInit {.. } isReady = do
65
76
let CWalletMeta {.. } = cwInitMeta
66
77
67
78
skey <- genSaveRootKey passphrase (bpToList cwBackupPhrase)
68
79
let cAddr = encToCId skey
69
80
70
- CWallet {.. } <- L. createWalletSafe cAddr cwInitMeta isReady
71
- -- can't return this result, since balances can change
81
+ eresult <- fmap Right (L. createWalletSafe cAddr cwInitMeta isReady)
82
+ `catch` \ (e :: WalletError ) ->
83
+ case e of
84
+ RequestError msg | msg == mnemonicExists ->
85
+ pure (Left cAddr)
86
+ _ ->
87
+ throwM e
88
+
89
+ for eresult $ \ CWallet {.. } -> do
72
90
73
- let accMeta = CAccountMeta { caName = " Initial account" }
74
- accInit = CAccountInit { caInitWId = cwId, caInitMeta = accMeta }
75
- () <$ L. newAccountIncludeUnready True (DeterminedSeed initialAccAddrIdxs) passphrase accInit
91
+ -- can't return this result, since balances can change
92
+
93
+ let accMeta = CAccountMeta { caName = " Initial account" }
94
+ accInit = CAccountInit { caInitWId = cwId, caInitMeta = accMeta }
95
+ () <$ L. newAccountIncludeUnready True (DeterminedSeed initialAccAddrIdxs) passphrase accInit
96
+
97
+ return (skey, cAddr)
76
98
77
- return (skey, cAddr)
78
99
79
100
newWallet :: L. MonadWalletLogic ctx m => PassPhrase -> CWalletInit -> m CWallet
80
- newWallet passphrase cwInit = do
101
+ newWallet = throwMnemonicExists ... newWalletNoThrow
102
+
103
+ newWalletNoThrow
104
+ :: L. MonadWalletLogic ctx m
105
+ => PassPhrase
106
+ -> CWalletInit
107
+ -> m (Either (CId Wal ) CWallet )
108
+ newWalletNoThrow passphrase cwInit = do
81
109
db <- askWalletDB
82
110
-- A brand new wallet doesn't need any syncing, so we mark isReady=True
83
- (_, wId) <- mkWallet passphrase cwInit True
84
- removeHistoryCache db wId
85
- -- BListener checks current syncTip before applying update,
86
- -- thus setting it up to date manually here
87
- withStateLockNoMetrics HighPriority $ \ tip -> setWalletSyncTip db wId tip
88
- L. getWallet wId
111
+ eresult <- mkWallet passphrase cwInit True
112
+ for eresult $ \ (_, wId) -> do
113
+ removeHistoryCache db wId
114
+ -- BListener checks current syncTip before applying update,
115
+ -- thus setting it up to date manually here
116
+ withStateLockNoMetrics HighPriority $ \ tip -> setWalletSyncTip db wId tip
117
+ L. getWallet wId
118
+
89
119
90
120
{- | Restores a wallet from a seed. The process is conceptually divided into
91
121
-- two parts:
92
122
-- 1. Recover this wallet balance from the global Utxo (fast, and synchronous);
93
123
-- 2. Recover the full transaction history from the blockchain (slow, asynchronous).
94
124
-}
95
- restoreWalletFromSeed :: ( L. MonadWalletLogic ctx m
96
- , MonadUnliftIO m
97
- , HasLens SyncQueue ctx SyncQueue
98
- ) => PassPhrase -> CWalletInit -> m CWallet
99
- restoreWalletFromSeed passphrase cwInit = do
100
- (sk, _) <- mkWallet passphrase cwInit False
101
- restoreWallet sk
125
+ restoreWalletFromSeed
126
+ :: ( L. MonadWalletLogic ctx m
127
+ , MonadUnliftIO m
128
+ , HasLens SyncQueue ctx SyncQueue
129
+ )
130
+ => PassPhrase
131
+ -> CWalletInit
132
+ -> m CWallet
133
+ restoreWalletFromSeed = throwMnemonicExists ... restoreWalletFromSeedNoThrow
134
+
135
+ throwMnemonicExists :: MonadThrow m => m (Either (CId Wal ) a ) -> m a
136
+ throwMnemonicExists m = m >>= \ case
137
+ Left _ -> throwM (RequestError mnemonicExists)
138
+ Right a -> pure a
139
+
140
+ -- | Restores a wallet without throwing an exception if the wallet already
141
+ -- exists.
142
+ restoreWalletFromSeedNoThrow
143
+ :: ( L. MonadWalletLogic ctx m
144
+ , MonadUnliftIO m
145
+ , HasLens SyncQueue ctx SyncQueue
146
+ )
147
+ => PassPhrase
148
+ -> CWalletInit
149
+ -> m (Either (CId Wal ) CWallet )
150
+ restoreWalletFromSeedNoThrow passphrase cwInit = do
151
+ eresult <- mkWallet passphrase cwInit False
152
+ for eresult $ \ (sk, _) -> restoreWallet sk
102
153
103
154
restoreWallet :: ( L. MonadWalletLogic ctx m
104
155
, MonadUnliftIO m
0 commit comments