@spacesops/wdk-react-native-core 1.0.0-beta.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (275) hide show
  1. package/README.md +551 -0
  2. package/dist/__mocks__/react.d.ts +40 -0
  3. package/dist/__mocks__/react.js +33 -0
  4. package/dist/__mocks__/react.js.map +1 -0
  5. package/dist/__mocks__/secureStorage.d.ts +26 -0
  6. package/dist/__mocks__/secureStorage.js +80 -0
  7. package/dist/__mocks__/secureStorage.js.map +1 -0
  8. package/dist/__tests__/hooks/useBalance.test.d.ts +6 -0
  9. package/dist/__tests__/hooks/useBalance.test.js +217 -0
  10. package/dist/__tests__/hooks/useBalance.test.js.map +1 -0
  11. package/dist/__tests__/hooks/useWallet.test.d.ts +6 -0
  12. package/dist/__tests__/hooks/useWallet.test.js +105 -0
  13. package/dist/__tests__/hooks/useWallet.test.js.map +1 -0
  14. package/dist/__tests__/hooks/useWalletManager.test.d.ts +6 -0
  15. package/dist/__tests__/hooks/useWalletManager.test.js +193 -0
  16. package/dist/__tests__/hooks/useWalletManager.test.js.map +1 -0
  17. package/dist/__tests__/hooks/useWdkApp.test.d.ts +6 -0
  18. package/dist/__tests__/hooks/useWdkApp.test.js +55 -0
  19. package/dist/__tests__/hooks/useWdkApp.test.js.map +1 -0
  20. package/dist/__tests__/hooks/useWorklet.test.d.ts +6 -0
  21. package/dist/__tests__/hooks/useWorklet.test.js +168 -0
  22. package/dist/__tests__/hooks/useWorklet.test.js.map +1 -0
  23. package/dist/__tests__/provider/WdkAppProvider.test.d.ts +6 -0
  24. package/dist/__tests__/provider/WdkAppProvider.test.js +57 -0
  25. package/dist/__tests__/provider/WdkAppProvider.test.js.map +1 -0
  26. package/dist/__tests__/services/accountService.test.d.ts +6 -0
  27. package/dist/__tests__/services/accountService.test.js +216 -0
  28. package/dist/__tests__/services/accountService.test.js.map +1 -0
  29. package/dist/__tests__/services/addressService.test.d.ts +6 -0
  30. package/dist/__tests__/services/addressService.test.js +246 -0
  31. package/dist/__tests__/services/addressService.test.js.map +1 -0
  32. package/dist/__tests__/services/balanceService.test.d.ts +6 -0
  33. package/dist/__tests__/services/balanceService.test.js +333 -0
  34. package/dist/__tests__/services/balanceService.test.js.map +1 -0
  35. package/dist/__tests__/services/walletSetupService.test.d.ts +6 -0
  36. package/dist/__tests__/services/walletSetupService.test.js +304 -0
  37. package/dist/__tests__/services/walletSetupService.test.js.map +1 -0
  38. package/dist/__tests__/services/walletSwitchingService.test.d.ts +6 -0
  39. package/dist/__tests__/services/walletSwitchingService.test.js +209 -0
  40. package/dist/__tests__/services/walletSwitchingService.test.js.map +1 -0
  41. package/dist/__tests__/services/workletLifecycleService.test.d.ts +6 -0
  42. package/dist/__tests__/services/workletLifecycleService.test.js +451 -0
  43. package/dist/__tests__/services/workletLifecycleService.test.js.map +1 -0
  44. package/dist/__tests__/setup.d.ts +7 -0
  45. package/dist/__tests__/setup.js +49 -0
  46. package/dist/__tests__/setup.js.map +1 -0
  47. package/dist/__tests__/storage/mmkvStorage.test.d.ts +6 -0
  48. package/dist/__tests__/storage/mmkvStorage.test.js +213 -0
  49. package/dist/__tests__/storage/mmkvStorage.test.js.map +1 -0
  50. package/dist/__tests__/store/walletStore.test.d.ts +4 -0
  51. package/dist/__tests__/store/walletStore.test.js +86 -0
  52. package/dist/__tests__/store/walletStore.test.js.map +1 -0
  53. package/dist/__tests__/store/workletStore.test.d.ts +4 -0
  54. package/dist/__tests__/store/workletStore.test.js +255 -0
  55. package/dist/__tests__/store/workletStore.test.js.map +1 -0
  56. package/dist/__tests__/types/hrpc.test.d.ts +4 -0
  57. package/dist/__tests__/types/hrpc.test.js +99 -0
  58. package/dist/__tests__/types/hrpc.test.js.map +1 -0
  59. package/dist/__tests__/utils/balanceUtils.test.d.ts +4 -0
  60. package/dist/__tests__/utils/balanceUtils.test.js +133 -0
  61. package/dist/__tests__/utils/balanceUtils.test.js.map +1 -0
  62. package/dist/__tests__/utils/errorHandling.test.d.ts +6 -0
  63. package/dist/__tests__/utils/errorHandling.test.js +119 -0
  64. package/dist/__tests__/utils/errorHandling.test.js.map +1 -0
  65. package/dist/__tests__/utils/errorUtils.test.d.ts +4 -0
  66. package/dist/__tests__/utils/errorUtils.test.js +133 -0
  67. package/dist/__tests__/utils/errorUtils.test.js.map +1 -0
  68. package/dist/__tests__/utils/initializationState.test.d.ts +6 -0
  69. package/dist/__tests__/utils/initializationState.test.js +243 -0
  70. package/dist/__tests__/utils/initializationState.test.js.map +1 -0
  71. package/dist/__tests__/utils/jsonUtils.test.d.ts +4 -0
  72. package/dist/__tests__/utils/jsonUtils.test.js +118 -0
  73. package/dist/__tests__/utils/jsonUtils.test.js.map +1 -0
  74. package/dist/__tests__/utils/mmkvKeyManager.test.d.ts +6 -0
  75. package/dist/__tests__/utils/mmkvKeyManager.test.js +158 -0
  76. package/dist/__tests__/utils/mmkvKeyManager.test.js.map +1 -0
  77. package/dist/__tests__/utils/mnemonicUtils.test.d.ts +4 -0
  78. package/dist/__tests__/utils/mnemonicUtils.test.js +40 -0
  79. package/dist/__tests__/utils/mnemonicUtils.test.js.map +1 -0
  80. package/dist/__tests__/utils/raceConditions.test.d.ts +6 -0
  81. package/dist/__tests__/utils/raceConditions.test.js +239 -0
  82. package/dist/__tests__/utils/raceConditions.test.js.map +1 -0
  83. package/dist/__tests__/utils/result.test.d.ts +4 -0
  84. package/dist/__tests__/utils/result.test.js +66 -0
  85. package/dist/__tests__/utils/result.test.js.map +1 -0
  86. package/dist/__tests__/utils/schemas.test.d.ts +4 -0
  87. package/dist/__tests__/utils/schemas.test.js +66 -0
  88. package/dist/__tests__/utils/schemas.test.js.map +1 -0
  89. package/dist/__tests__/utils/storeHelpers.test.d.ts +4 -0
  90. package/dist/__tests__/utils/storeHelpers.test.js +227 -0
  91. package/dist/__tests__/utils/storeHelpers.test.js.map +1 -0
  92. package/dist/__tests__/utils/typeGuards.test.d.ts +4 -0
  93. package/dist/__tests__/utils/typeGuards.test.js +175 -0
  94. package/dist/__tests__/utils/typeGuards.test.js.map +1 -0
  95. package/dist/__tests__/utils/validation.test.d.ts +4 -0
  96. package/dist/__tests__/utils/validation.test.js +126 -0
  97. package/dist/__tests__/utils/validation.test.js.map +1 -0
  98. package/dist/__tests__/utils/walletUtils.test.d.ts +4 -0
  99. package/dist/__tests__/utils/walletUtils.test.js +156 -0
  100. package/dist/__tests__/utils/walletUtils.test.js.map +1 -0
  101. package/dist/hooks/useBalance.d.ts +170 -0
  102. package/dist/hooks/useBalance.js +442 -0
  103. package/dist/hooks/useBalance.js.map +1 -0
  104. package/dist/hooks/useWallet.d.ts +43 -0
  105. package/dist/hooks/useWallet.js +193 -0
  106. package/dist/hooks/useWallet.js.map +1 -0
  107. package/dist/hooks/useWalletManager.d.ts +100 -0
  108. package/dist/hooks/useWalletManager.js +526 -0
  109. package/dist/hooks/useWalletManager.js.map +1 -0
  110. package/dist/hooks/useWdkApp.d.ts +66 -0
  111. package/dist/hooks/useWdkApp.js +74 -0
  112. package/dist/hooks/useWdkApp.js.map +1 -0
  113. package/dist/hooks/useWorklet.d.ts +66 -0
  114. package/dist/hooks/useWorklet.js +42 -0
  115. package/dist/hooks/useWorklet.js.map +1 -0
  116. package/dist/index.d.ts +33 -0
  117. package/dist/index.js +36 -0
  118. package/dist/index.js.map +1 -0
  119. package/dist/provider/WdkAppProvider.d.ts +112 -0
  120. package/dist/provider/WdkAppProvider.js +558 -0
  121. package/dist/provider/WdkAppProvider.js.map +1 -0
  122. package/dist/services/accountService.d.ts +52 -0
  123. package/dist/services/accountService.js +119 -0
  124. package/dist/services/accountService.js.map +1 -0
  125. package/dist/services/addressService.d.ts +22 -0
  126. package/dist/services/addressService.js +110 -0
  127. package/dist/services/addressService.js.map +1 -0
  128. package/dist/services/balanceService.d.ts +114 -0
  129. package/dist/services/balanceService.js +208 -0
  130. package/dist/services/balanceService.js.map +1 -0
  131. package/dist/services/walletSetupService.d.ts +217 -0
  132. package/dist/services/walletSetupService.js +535 -0
  133. package/dist/services/walletSetupService.js.map +1 -0
  134. package/dist/services/walletSwitchingService.d.ts +48 -0
  135. package/dist/services/walletSwitchingService.js +143 -0
  136. package/dist/services/walletSwitchingService.js.map +1 -0
  137. package/dist/services/workletLifecycleService.d.ts +117 -0
  138. package/dist/services/workletLifecycleService.js +433 -0
  139. package/dist/services/workletLifecycleService.js.map +1 -0
  140. package/dist/storage/mmkvStorage.d.ts +44 -0
  141. package/dist/storage/mmkvStorage.js +348 -0
  142. package/dist/storage/mmkvStorage.js.map +1 -0
  143. package/dist/store/walletStore.d.ts +130 -0
  144. package/dist/store/walletStore.js +204 -0
  145. package/dist/store/walletStore.js.map +1 -0
  146. package/dist/store/workletStore.d.ts +121 -0
  147. package/dist/store/workletStore.js +256 -0
  148. package/dist/store/workletStore.js.map +1 -0
  149. package/dist/types/hrpc.d.ts +60 -0
  150. package/dist/types/hrpc.js +26 -0
  151. package/dist/types/hrpc.js.map +1 -0
  152. package/dist/types.d.ts +168 -0
  153. package/dist/types.js +7 -0
  154. package/dist/types.js.map +1 -0
  155. package/dist/utils/balanceUtils.d.ts +30 -0
  156. package/dist/utils/balanceUtils.js +86 -0
  157. package/dist/utils/balanceUtils.js.map +1 -0
  158. package/dist/utils/constants.d.ts +66 -0
  159. package/dist/utils/constants.js +73 -0
  160. package/dist/utils/constants.js.map +1 -0
  161. package/dist/utils/errorHandling.d.ts +47 -0
  162. package/dist/utils/errorHandling.js +54 -0
  163. package/dist/utils/errorHandling.js.map +1 -0
  164. package/dist/utils/errorUtils.d.ts +89 -0
  165. package/dist/utils/errorUtils.js +264 -0
  166. package/dist/utils/errorUtils.js.map +1 -0
  167. package/dist/utils/initializationState.d.ts +129 -0
  168. package/dist/utils/initializationState.js +220 -0
  169. package/dist/utils/initializationState.js.map +1 -0
  170. package/dist/utils/jsonUtils.d.ts +21 -0
  171. package/dist/utils/jsonUtils.js +67 -0
  172. package/dist/utils/jsonUtils.js.map +1 -0
  173. package/dist/utils/logger.d.ts +27 -0
  174. package/dist/utils/logger.js +50 -0
  175. package/dist/utils/logger.js.map +1 -0
  176. package/dist/utils/mmkvKeyManager.d.ts +57 -0
  177. package/dist/utils/mmkvKeyManager.js +214 -0
  178. package/dist/utils/mmkvKeyManager.js.map +1 -0
  179. package/dist/utils/mnemonicUtils.d.ts +17 -0
  180. package/dist/utils/mnemonicUtils.js +28 -0
  181. package/dist/utils/mnemonicUtils.js.map +1 -0
  182. package/dist/utils/operationMutex.d.ts +69 -0
  183. package/dist/utils/operationMutex.js +150 -0
  184. package/dist/utils/operationMutex.js.map +1 -0
  185. package/dist/utils/result.d.ts +34 -0
  186. package/dist/utils/result.js +43 -0
  187. package/dist/utils/result.js.map +1 -0
  188. package/dist/utils/schemas.d.ts +365 -0
  189. package/dist/utils/schemas.js +152 -0
  190. package/dist/utils/schemas.js.map +1 -0
  191. package/dist/utils/storeHelpers.d.ts +112 -0
  192. package/dist/utils/storeHelpers.js +198 -0
  193. package/dist/utils/storeHelpers.js.map +1 -0
  194. package/dist/utils/typeGuards.d.ts +70 -0
  195. package/dist/utils/typeGuards.js +95 -0
  196. package/dist/utils/typeGuards.js.map +1 -0
  197. package/dist/utils/validation.d.ts +53 -0
  198. package/dist/utils/validation.js +152 -0
  199. package/dist/utils/validation.js.map +1 -0
  200. package/dist/utils/walletStateHelpers.d.ts +62 -0
  201. package/dist/utils/walletStateHelpers.js +81 -0
  202. package/dist/utils/walletStateHelpers.js.map +1 -0
  203. package/dist/utils/walletUtils.d.ts +38 -0
  204. package/dist/utils/walletUtils.js +87 -0
  205. package/dist/utils/walletUtils.js.map +1 -0
  206. package/package.json +79 -0
  207. package/src/__mocks__/react.ts +34 -0
  208. package/src/__mocks__/secureStorage.ts +87 -0
  209. package/src/__tests__/hooks/useBalance.test.ts +286 -0
  210. package/src/__tests__/hooks/useWallet.test.ts +122 -0
  211. package/src/__tests__/hooks/useWalletManager.test.ts +271 -0
  212. package/src/__tests__/hooks/useWdkApp.test.tsx +59 -0
  213. package/src/__tests__/hooks/useWorklet.test.ts +195 -0
  214. package/src/__tests__/provider/WdkAppProvider.test.tsx +67 -0
  215. package/src/__tests__/services/accountService.test.ts +337 -0
  216. package/src/__tests__/services/addressService.test.ts +312 -0
  217. package/src/__tests__/services/balanceService.test.ts +411 -0
  218. package/src/__tests__/services/walletSetupService.test.ts +463 -0
  219. package/src/__tests__/services/walletSwitchingService.test.ts +258 -0
  220. package/src/__tests__/services/workletLifecycleService.test.ts +514 -0
  221. package/src/__tests__/setup.ts +54 -0
  222. package/src/__tests__/storage/mmkvStorage.test.ts +325 -0
  223. package/src/__tests__/store/walletStore.test.ts +101 -0
  224. package/src/__tests__/store/workletStore.test.ts +329 -0
  225. package/src/__tests__/types/hrpc.test.ts +125 -0
  226. package/src/__tests__/utils/balanceUtils.test.ts +151 -0
  227. package/src/__tests__/utils/errorHandling.test.ts +147 -0
  228. package/src/__tests__/utils/errorUtils.test.ts +170 -0
  229. package/src/__tests__/utils/initializationState.test.ts +337 -0
  230. package/src/__tests__/utils/jsonUtils.test.ts +131 -0
  231. package/src/__tests__/utils/mmkvKeyManager.test.ts +205 -0
  232. package/src/__tests__/utils/mnemonicUtils.test.ts +48 -0
  233. package/src/__tests__/utils/raceConditions.test.ts +292 -0
  234. package/src/__tests__/utils/result.test.ts +73 -0
  235. package/src/__tests__/utils/schemas.test.ts +82 -0
  236. package/src/__tests__/utils/storeHelpers.test.ts +323 -0
  237. package/src/__tests__/utils/typeGuards.test.ts +209 -0
  238. package/src/__tests__/utils/validation.test.ts +152 -0
  239. package/src/__tests__/utils/walletUtils.test.ts +195 -0
  240. package/src/hooks/useBalance.ts +597 -0
  241. package/src/hooks/useWallet.ts +288 -0
  242. package/src/hooks/useWalletManager.ts +654 -0
  243. package/src/hooks/useWdkApp.ts +78 -0
  244. package/src/hooks/useWorklet.ts +109 -0
  245. package/src/index.ts +112 -0
  246. package/src/provider/WdkAppProvider.tsx +764 -0
  247. package/src/services/accountService.ts +134 -0
  248. package/src/services/addressService.ts +125 -0
  249. package/src/services/balanceService.ts +291 -0
  250. package/src/services/walletSetupService.ts +695 -0
  251. package/src/services/walletSwitchingService.ts +157 -0
  252. package/src/services/workletLifecycleService.ts +561 -0
  253. package/src/storage/mmkvStorage.ts +417 -0
  254. package/src/store/walletStore.ts +301 -0
  255. package/src/store/workletStore.ts +340 -0
  256. package/src/types/hrpc.ts +78 -0
  257. package/src/types.ts +188 -0
  258. package/src/utils/balanceUtils.ts +96 -0
  259. package/src/utils/constants.ts +84 -0
  260. package/src/utils/errorHandling.md +163 -0
  261. package/src/utils/errorHandling.ts +61 -0
  262. package/src/utils/errorUtils.ts +300 -0
  263. package/src/utils/initializationState.ts +242 -0
  264. package/src/utils/jsonUtils.ts +75 -0
  265. package/src/utils/logger.ts +54 -0
  266. package/src/utils/mmkvKeyManager.ts +256 -0
  267. package/src/utils/mnemonicUtils.ts +35 -0
  268. package/src/utils/operationMutex.ts +181 -0
  269. package/src/utils/result.ts +57 -0
  270. package/src/utils/schemas.ts +190 -0
  271. package/src/utils/storeHelpers.ts +236 -0
  272. package/src/utils/typeGuards.ts +129 -0
  273. package/src/utils/validation.ts +174 -0
  274. package/src/utils/walletStateHelpers.ts +104 -0
  275. package/src/utils/walletUtils.ts +107 -0
@@ -0,0 +1,654 @@
1
+ /**
2
+ * Wallet Manager Hook
3
+ *
4
+ * Consolidated hook for wallet setup, initialization, and lifecycle management.
5
+ * This is the ONLY hook for wallet lifecycle operations.
6
+ *
7
+ * PURPOSE: Use this hook for wallet setup/auth flows (creating new wallets,
8
+ * loading existing wallets, checking if wallet exists, deleting wallets, getting mnemonic).
9
+ *
10
+ * When to use which hook:
11
+ * - **App initialization state**: Use `useWdkApp()` to check if app is ready
12
+ * - **Wallet lifecycle** (create, load, import, delete): Use this hook (`useWalletManager()`)
13
+ * - **Wallet operations** (addresses, account methods): Use `useWallet()` AFTER initialization
14
+ * - **Balance fetching**: Use `useBalance()` hook with TanStack Query
15
+ *
16
+ * **Wallet Switching**: Use `useWallet({ walletId })` to switch wallets.
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * // Check if app is ready first
21
+ * const { isReady } = useWdkApp()
22
+ *
23
+ * // Then use wallet manager for lifecycle operations
24
+ * // networkConfigs is optional - it will be retrieved from workletStore if not provided
25
+ * const {
26
+ * createWallet,
27
+ * initializeWallet,
28
+ * initializeFromMnemonic,
29
+ * hasWallet,
30
+ * deleteWallet,
31
+ * getMnemonic,
32
+ * createTemporaryWallet,
33
+ * isInitializing,
34
+ * error
35
+ * } = useWalletManager('user@example.com')
36
+ *
37
+ * // Create new wallet (persistent, requires biometrics)
38
+ * // networkConfigs can be passed here or retrieved from store
39
+ * await createWallet('user@example.com', networkConfigs)
40
+ *
41
+ * // Initialize wallet (create new or load existing)
42
+ * await initializeWallet({ createNew: true })
43
+ *
44
+ * // Load existing wallet (requires biometric authentication)
45
+ * await initializeWallet({ createNew: false })
46
+ *
47
+ * // Import from mnemonic
48
+ * await initializeFromMnemonic('word1 word2 ... word12')
49
+ *
50
+ * // Create temporary wallet for previewing addresses (no biometrics, not saved)
51
+ * await createTemporaryWallet()
52
+ *
53
+ * // Get mnemonic (requires biometric authentication if not cached)
54
+ * const mnemonic = await getMnemonic()
55
+ *
56
+ * // Delete wallet
57
+ * await deleteWallet()
58
+ * ```
59
+ */
60
+
61
+ import { useCallback, useMemo, useState } from 'react'
62
+ import { useShallow } from 'zustand/react/shallow'
63
+
64
+ import { WalletSetupService } from '../services/walletSetupService'
65
+ import { WorkletLifecycleService } from '../services/workletLifecycleService'
66
+ import { getWalletStore } from '../store/walletStore'
67
+ import { getWorkletStore } from '../store/workletStore'
68
+ import { updateWalletLoadingState, isWalletLoadingState, getWalletIdFromLoadingState } from '../store/walletStore'
69
+ import { withOperationMutex } from '../utils/operationMutex'
70
+ import { log, logError } from '../utils/logger'
71
+ import type { NetworkConfigs } from '../types'
72
+ import type { WalletInfo } from '../store/walletStore'
73
+
74
+ // Re-export WalletInfo for backward compatibility
75
+ export type { WalletInfo }
76
+
77
+ export interface UseWalletManagerResult {
78
+ /** Initialize wallet - either create new or load existing */
79
+ initializeWallet: (options?: { createNew?: boolean; walletId?: string }) => Promise<void>
80
+ /** Initialize wallet from mnemonic seedphrase */
81
+ initializeFromMnemonic: (mnemonic: string, walletId?: string) => Promise<void>
82
+ /** Check if wallet exists */
83
+ hasWallet: (walletId?: string) => Promise<boolean>
84
+ /** Delete wallet */
85
+ deleteWallet: (walletId?: string) => Promise<void>
86
+ /** Get mnemonic phrase (requires biometric authentication if not cached) */
87
+ getMnemonic: (walletId?: string) => Promise<string | null>
88
+ /** Create a temporary wallet for previewing addresses (no biometrics, not saved) */
89
+ createTemporaryWallet: () => Promise<void>
90
+ /** Whether initialization is in progress */
91
+ isInitializing: boolean
92
+ /** Error message if any */
93
+ error: string | null
94
+ /** Clear error state */
95
+ clearError: () => void
96
+ /** Clear active wallet ID (useful when switching users or logging out) */
97
+ clearActiveWallet: () => void
98
+ // Wallet list operations (merged from useWalletList)
99
+ /** List of all known wallets */
100
+ wallets: WalletInfo[]
101
+ /** Currently active wallet identifier */
102
+ activeWalletId: string | null
103
+ /** Create a new wallet with the given walletId (adds to list) */
104
+ createWallet: (walletId: string, networkConfigs?: NetworkConfigs) => Promise<void>
105
+ /** Refresh the wallet list */
106
+ refreshWalletList: (knownIdentifiers?: string[]) => Promise<void>
107
+ /** Whether wallet list operation is in progress */
108
+ isWalletListLoading: boolean
109
+ /** Wallet list error message if any */
110
+ walletListError: string | null
111
+ }
112
+
113
+ export function useWalletManager(
114
+ walletId?: string,
115
+ networkConfigs?: NetworkConfigs
116
+ ): UseWalletManagerResult {
117
+ const [error, setError] = useState<string | null>(null)
118
+
119
+ // Local loading and error state for wallet list operations (ephemeral, only used in this hook)
120
+ const [isWalletListLoading, setIsWalletListLoading] = useState(false)
121
+ const [walletListError, setWalletListError] = useState<string | null>(null)
122
+
123
+ const walletStore = getWalletStore()
124
+ const workletStore = getWorkletStore()
125
+
126
+ /**
127
+ * Get networkConfigs from parameter or workletStore
128
+ * Throws error if not available from either source
129
+ */
130
+ const getNetworkConfigs = useCallback((): NetworkConfigs => {
131
+ const networkConfigsFromStore = workletStore.getState().networkConfigs
132
+ const effectiveNetworkConfigs = networkConfigs ?? networkConfigsFromStore
133
+
134
+ if (!effectiveNetworkConfigs) {
135
+ throw new Error(
136
+ 'networkConfigs is required. Either provide it as a parameter or ensure the worklet is started with networkConfigs.'
137
+ )
138
+ }
139
+
140
+ return effectiveNetworkConfigs
141
+ }, [networkConfigs])
142
+ // Note: workletStore removed from deps - it's a singleton that never changes
143
+
144
+ // Subscribe to wallet list state and loading state from Zustand
145
+ const walletListState = walletStore(
146
+ useShallow((state: import('../store/walletStore').WalletStore) => ({
147
+ wallets: state.walletList,
148
+ activeWalletId: state.activeWalletId,
149
+ walletLoadingState: state.walletLoadingState,
150
+ }))
151
+ )
152
+
153
+ // Derive isInitializing from walletLoadingState (single source of truth)
154
+ // Check if the current walletId matches the loading state identifier
155
+ const isInitializing = useMemo(() => {
156
+ const loadingState = walletListState.walletLoadingState
157
+ const currentWalletId = walletId || walletListState.activeWalletId
158
+ const loadingWalletId = getWalletIdFromLoadingState(loadingState)
159
+
160
+ // Only consider it initializing if:
161
+ // 1. The loading state indicates loading/checking
162
+ // 2. The walletId matches (or no walletId specified, meaning we're tracking active wallet)
163
+ return isWalletLoadingState(loadingState) &&
164
+ (currentWalletId === null || currentWalletId === loadingWalletId || walletId === undefined)
165
+ }, [walletListState.walletLoadingState, walletId, walletListState.activeWalletId])
166
+
167
+ /**
168
+ * Initialize wallet - either create new or load existing
169
+ *
170
+ * @param options - Wallet initialization options
171
+ * @param options.createNew - If true, creates a new wallet; if false, loads existing wallet
172
+ * @param options.walletId - Optional walletId override (defaults to hook's walletId)
173
+ */
174
+ const initializeWallet = useCallback(
175
+ async (options: { createNew?: boolean; walletId?: string } = {}) => {
176
+ setError(null)
177
+ const targetWalletId = options.walletId ?? walletId
178
+ const walletStore = getWalletStore()
179
+ const effectiveNetworkConfigs = getNetworkConfigs()
180
+
181
+ try {
182
+ // Check if wallet is already ready before attempting to initialize
183
+ // This prevents unnecessary initialization calls when the wallet is already loaded
184
+ if (targetWalletId) {
185
+ const currentWalletState = walletStore.getState().walletLoadingState
186
+ if (currentWalletState.type === 'ready' && currentWalletState.identifier === targetWalletId) {
187
+ log('[useWalletManager] Wallet already ready - skipping initialization', { targetWalletId })
188
+ return
189
+ }
190
+ }
191
+
192
+ // Update loading state in store (single source of truth)
193
+ if (targetWalletId) {
194
+ walletStore.setState((prev) => updateWalletLoadingState(prev, {
195
+ type: 'loading',
196
+ identifier: targetWalletId,
197
+ walletExists: true,
198
+ }))
199
+ }
200
+
201
+ await WalletSetupService.initializeWallet(
202
+ effectiveNetworkConfigs,
203
+ {
204
+ ...options,
205
+ walletId: targetWalletId,
206
+ }
207
+ )
208
+
209
+ // Mark as ready on success
210
+ // Wallet is ready when initializeWDK() completes successfully, even if addresses don't exist yet
211
+ // (Addresses are lazy-loaded when getAddress() is called)
212
+ // This matches the pattern used in WalletSwitchingService.switchToWallet()
213
+ if (targetWalletId) {
214
+ walletStore.setState((prev) => {
215
+ const currentState = prev.walletLoadingState
216
+ const addresses = prev.addresses[targetWalletId]
217
+ const hasAddresses = !!(addresses && Object.keys(addresses).length > 0)
218
+
219
+ // If addresses exist, we can set to ready if state allows it
220
+ // WdkAppProvider will also handle transitions when addresses appear
221
+ if (hasAddresses) {
222
+ // Only set to ready if current state allows the transition
223
+ // Valid transitions to ready: from 'loading' or 'checking'
224
+ if (currentState.type === 'loading' || currentState.type === 'checking') {
225
+ const readyStateUpdate = updateWalletLoadingState(prev, {
226
+ type: 'ready',
227
+ identifier: targetWalletId,
228
+ })
229
+ // Also set activeWalletId to prevent WdkAppProvider from resetting state
230
+ return {
231
+ ...readyStateUpdate,
232
+ activeWalletId: targetWalletId,
233
+ }
234
+ }
235
+ // If state is 'not_loaded', let WdkAppProvider handle it (it will transition when addresses exist)
236
+ // If state is already 'ready', don't change it
237
+ return prev
238
+ }
239
+
240
+ // If no addresses yet, set to ready if state is 'loading' or 'checking' (normal case)
241
+ // The wallet is ready when WDK is initialized with correct credentials, addresses can be fetched lazily
242
+ // Note: Cannot transition from 'not_loaded' directly to 'ready' - must go through 'loading' first
243
+ if (currentState.type === 'loading' || currentState.type === 'checking') {
244
+ const readyStateUpdate = updateWalletLoadingState(prev, {
245
+ type: 'ready',
246
+ identifier: targetWalletId,
247
+ })
248
+ // Also set activeWalletId to prevent WdkAppProvider from resetting state
249
+ return {
250
+ ...readyStateUpdate,
251
+ activeWalletId: targetWalletId,
252
+ }
253
+ } else if (currentState.type === 'not_loaded') {
254
+ // State was reset to not_loaded by WdkAppProvider
255
+ // We need to transition through 'loading' first, then 'ready'
256
+ // Since initializeWDK() already completed successfully, we can do both transitions
257
+ // in sequence within the same setState call
258
+ log('[useWalletManager] State reset to not_loaded, transitioning through loading to ready', {
259
+ targetWalletId,
260
+ hasAddresses,
261
+ })
262
+ // First transition: not_loaded -> loading
263
+ const loadingStateUpdate = updateWalletLoadingState(prev, {
264
+ type: 'loading',
265
+ identifier: targetWalletId,
266
+ walletExists: true,
267
+ })
268
+ // Second transition: loading -> ready (using the updated state)
269
+ const readyStateUpdate = updateWalletLoadingState(
270
+ { ...prev, ...loadingStateUpdate } as typeof prev,
271
+ {
272
+ type: 'ready',
273
+ identifier: targetWalletId,
274
+ }
275
+ )
276
+ // Also set activeWalletId to prevent WdkAppProvider from resetting state
277
+ return {
278
+ ...readyStateUpdate,
279
+ activeWalletId: targetWalletId,
280
+ }
281
+ } else {
282
+ // State is 'ready' or 'error' - don't change it
283
+ log('[useWalletManager] Wallet already in final state, not changing', {
284
+ currentState: currentState.type,
285
+ targetWalletId,
286
+ hasAddresses,
287
+ })
288
+ return prev
289
+ }
290
+ })
291
+ }
292
+ } catch (err) {
293
+ const errorMessage =
294
+ err instanceof Error ? err.message : String(err)
295
+ const errorObj = err instanceof Error ? err : new Error(String(err))
296
+ logError('Failed to initialize wallet:', err)
297
+ setError(errorMessage)
298
+
299
+ // Cleanup state on error
300
+ if (targetWalletId) {
301
+ walletStore.setState((prev) => updateWalletLoadingState(prev, {
302
+ type: 'error',
303
+ identifier: targetWalletId,
304
+ error: errorObj,
305
+ }))
306
+ }
307
+
308
+ throw err
309
+ }
310
+ },
311
+ [getNetworkConfigs, walletId]
312
+ )
313
+
314
+ /**
315
+ * Check if wallet exists
316
+ *
317
+ * @param walletId - Optional walletId override (defaults to hook's walletId)
318
+ * @returns Promise resolving to true if wallet exists, false otherwise
319
+ */
320
+ const hasWallet = useCallback(
321
+ async (walletIdParam?: string): Promise<boolean> => {
322
+ return WalletSetupService.hasWallet(walletIdParam ?? walletId)
323
+ },
324
+ [walletId]
325
+ )
326
+
327
+ /**
328
+ * Initialize wallet from mnemonic seedphrase
329
+ *
330
+ * @param mnemonic - Mnemonic phrase to import
331
+ * @param walletId - Optional walletId override (defaults to hook's walletId)
332
+ */
333
+ const initializeFromMnemonic = useCallback(
334
+ async (mnemonic: string, walletIdParam?: string) => {
335
+ setError(null)
336
+ const targetWalletId = walletIdParam ?? walletId
337
+ const walletStore = getWalletStore()
338
+ const effectiveNetworkConfigs = getNetworkConfigs()
339
+
340
+ try {
341
+ // Update loading state in store (single source of truth)
342
+ if (targetWalletId) {
343
+ walletStore.setState((prev) => updateWalletLoadingState(prev, {
344
+ type: 'loading',
345
+ identifier: targetWalletId,
346
+ walletExists: false, // New wallet from mnemonic
347
+ }))
348
+ }
349
+
350
+ await WalletSetupService.initializeFromMnemonic(
351
+ effectiveNetworkConfigs,
352
+ mnemonic,
353
+ targetWalletId
354
+ )
355
+
356
+ // Mark as ready on success
357
+ if (targetWalletId) {
358
+ walletStore.setState((prev) => updateWalletLoadingState(prev, {
359
+ type: 'ready',
360
+ identifier: targetWalletId,
361
+ }))
362
+ }
363
+ } catch (err) {
364
+ const errorMessage =
365
+ err instanceof Error ? err.message : String(err)
366
+ const errorObj = err instanceof Error ? err : new Error(String(err))
367
+ logError('Failed to initialize wallet from mnemonic:', err)
368
+ setError(errorMessage)
369
+
370
+ // Cleanup state on error
371
+ if (targetWalletId) {
372
+ walletStore.setState((prev) => updateWalletLoadingState(prev, {
373
+ type: 'error',
374
+ identifier: targetWalletId,
375
+ error: errorObj,
376
+ }))
377
+ }
378
+
379
+ throw err
380
+ }
381
+ },
382
+ [getNetworkConfigs, walletId]
383
+ )
384
+
385
+ /**
386
+ * Delete wallet
387
+ *
388
+ * @param walletId - Optional walletId override (defaults to hook's walletId)
389
+ * If not provided, deletes the default wallet
390
+ */
391
+ const deleteWallet = useCallback(
392
+ async (walletIdParam?: string) => {
393
+ setError(null)
394
+
395
+ try {
396
+ const targetWalletId = walletIdParam ?? walletId
397
+ if (!targetWalletId) {
398
+ throw new Error('Wallet ID is required for deletion')
399
+ }
400
+
401
+ await WalletSetupService.deleteWallet(targetWalletId)
402
+
403
+ // Remove from wallet list and clear all wallet-specific data
404
+ walletStore.setState((state: import('../store/walletStore').WalletStore) => {
405
+ const wasActive = state.activeWalletId === targetWalletId
406
+
407
+ // Clear all wallet-specific data (only if walletId exists)
408
+ const remainingAddresses = { ...state.addresses }
409
+ const remainingBalances = { ...state.balances }
410
+ const remainingAccountList = { ...state.accountList }
411
+ const remainingLastBalanceUpdate = { ...state.lastBalanceUpdate }
412
+ const remainingWalletLoading = { ...state.walletLoading }
413
+ const remainingBalanceLoading = { ...state.balanceLoading }
414
+
415
+ delete remainingAddresses[targetWalletId]
416
+ delete remainingBalances[targetWalletId]
417
+ delete remainingAccountList[targetWalletId]
418
+ delete remainingLastBalanceUpdate[targetWalletId]
419
+ delete remainingWalletLoading[targetWalletId]
420
+ delete remainingBalanceLoading[targetWalletId]
421
+
422
+ return {
423
+ walletList: state.walletList.filter((w: import('../store/walletStore').WalletInfo) => w.identifier !== targetWalletId),
424
+ activeWalletId: wasActive ? null : state.activeWalletId,
425
+ // Reset loading state if this was the active wallet
426
+ walletLoadingState: wasActive ? { type: 'not_loaded' } : state.walletLoadingState,
427
+ // Clear all wallet-specific data
428
+ addresses: remainingAddresses,
429
+ balances: remainingBalances,
430
+ accountList: remainingAccountList,
431
+ lastBalanceUpdate: remainingLastBalanceUpdate,
432
+ walletLoading: remainingWalletLoading,
433
+ balanceLoading: remainingBalanceLoading,
434
+ }
435
+ })
436
+
437
+ log(`[useWalletManager] Deleted wallet and cleared all data: ${targetWalletId}`)
438
+ } catch (err) {
439
+ const errorMessage =
440
+ err instanceof Error ? err.message : String(err)
441
+ logError('Failed to delete wallet:', err)
442
+ setError(errorMessage)
443
+ throw err
444
+ }
445
+ },
446
+ [walletId]
447
+ )
448
+
449
+ /**
450
+ * Get mnemonic phrase from wallet
451
+ * Requires biometric authentication if credentials are not cached
452
+ *
453
+ * @param walletId - Optional walletId override (defaults to hook's walletId)
454
+ * @returns Promise resolving to mnemonic phrase or null if not found
455
+ */
456
+ const getMnemonic = useCallback(
457
+ async (walletIdParam?: string): Promise<string | null> => {
458
+ try {
459
+ return await WalletSetupService.getMnemonic(walletIdParam ?? walletId)
460
+ } catch (err) {
461
+ const errorMessage =
462
+ err instanceof Error ? err.message : String(err)
463
+ logError('Failed to get mnemonic:', err)
464
+ throw err
465
+ }
466
+ },
467
+ [walletId]
468
+ )
469
+
470
+ /**
471
+ * Clear error state
472
+ */
473
+ const clearError = useCallback(() => {
474
+ setError(null)
475
+ }, [])
476
+
477
+ /**
478
+ * Clear active wallet ID
479
+ * Useful when switching users or logging out to prevent auto-initialization with wrong wallet
480
+ */
481
+ const clearActiveWallet = useCallback(() => {
482
+ walletStore.setState({ activeWalletId: null })
483
+ log('[useWalletManager] Cleared active wallet ID')
484
+ }, [])
485
+
486
+ /**
487
+ * Create a temporary wallet for previewing addresses
488
+ * This creates a wallet in memory only (no biometrics, not saved to secure storage)
489
+ * Useful for previewing addresses before committing to creating a real wallet
490
+ */
491
+ const createTemporaryWallet = useCallback(async () => {
492
+ return withOperationMutex('createTemporaryWallet', async () => {
493
+ setError(null)
494
+
495
+ try {
496
+ const effectiveNetworkConfigs = getNetworkConfigs()
497
+
498
+ // Ensure worklet is started (auto-start if needed)
499
+ await WorkletLifecycleService.ensureWorkletStarted(
500
+ effectiveNetworkConfigs,
501
+ { autoStart: true }
502
+ )
503
+
504
+ // Generate entropy and encrypt (no biometrics, no keychain save)
505
+ const result = await WorkletLifecycleService.generateEntropyAndEncrypt()
506
+
507
+ // Initialize WDK with temporary credentials
508
+ await WorkletLifecycleService.initializeWDK({
509
+ encryptionKey: result.encryptionKey,
510
+ encryptedSeed: result.encryptedSeedBuffer,
511
+ })
512
+
513
+ // Don't update activeWalletId for temporary wallet (it's not a real wallet)
514
+ // Temporary wallets don't affect walletLoadingState
515
+ log('[useWalletManager] Temporary wallet created successfully')
516
+ } catch (err) {
517
+ const errorMessage = err instanceof Error ? err.message : String(err)
518
+ const errorObj = err instanceof Error ? err : new Error(String(err))
519
+ logError('[useWalletManager] Failed to create temporary wallet:', err)
520
+ setError(errorMessage)
521
+ throw err
522
+ }
523
+ })
524
+ }, [getNetworkConfigs])
525
+
526
+ /**
527
+ * Check if a wallet exists (for wallet list operations)
528
+ */
529
+ const checkWallet = useCallback(async (walletId: string): Promise<boolean> => {
530
+ try {
531
+ return await WalletSetupService.hasWallet(walletId)
532
+ } catch (err) {
533
+ logError('Failed to check wallet:', err)
534
+ return false
535
+ }
536
+ }, [])
537
+
538
+ /**
539
+ * Refresh the wallet list
540
+ */
541
+ const refreshWalletList = useCallback(async (knownIdentifiers?: string[]) => {
542
+ setIsWalletListLoading(true)
543
+ setWalletListError(null)
544
+
545
+ try {
546
+ const identifiersToCheck = knownIdentifiers || []
547
+ const currentActiveId = walletStore.getState().activeWalletId
548
+
549
+ // If no known identifiers provided, check default wallet
550
+ if (identifiersToCheck.length === 0) {
551
+ const defaultExists = await checkWallet('default')
552
+ walletStore.setState({
553
+ walletList: [{ identifier: 'default', exists: defaultExists, isActive: currentActiveId === 'default' }],
554
+ })
555
+ } else {
556
+ // Check all known identifiers
557
+ const walletChecks = await Promise.all(
558
+ identifiersToCheck.map(async (id) => ({
559
+ identifier: id,
560
+ exists: await checkWallet(id),
561
+ isActive: currentActiveId === id,
562
+ }))
563
+ )
564
+ walletStore.setState({ walletList: walletChecks })
565
+ }
566
+ } catch (err) {
567
+ const errorMessage = err instanceof Error ? err.message : String(err)
568
+ logError('Failed to refresh wallet list:', err)
569
+ setWalletListError(errorMessage)
570
+ } finally {
571
+ setIsWalletListLoading(false)
572
+ }
573
+ }, [checkWallet])
574
+
575
+
576
+ /**
577
+ * Create a new wallet and add it to the wallet list
578
+ */
579
+ const createWallet = useCallback(async (walletId: string, walletNetworkConfigs?: NetworkConfigs) => {
580
+ setIsWalletListLoading(true)
581
+ setWalletListError(null)
582
+
583
+ try {
584
+ // Check if wallet already exists
585
+ const exists = await checkWallet(walletId)
586
+ if (exists) {
587
+ throw new Error(`Wallet with walletId "${walletId}" already exists`)
588
+ }
589
+
590
+ // Use provided networkConfigs or get from store
591
+ const effectiveNetworkConfigs = walletNetworkConfigs ?? getNetworkConfigs()
592
+
593
+ // Create wallet using WalletSetupService
594
+ await WalletSetupService.createNewWallet(effectiveNetworkConfigs, walletId)
595
+
596
+ // Add to wallet list and set as active wallet
597
+ walletStore.setState((state: import('../store/walletStore').WalletStore) => ({
598
+ walletList: [...state.walletList, { identifier: walletId, exists: true, isActive: true }],
599
+ activeWalletId: walletId, // Set as active wallet so WdkAppProvider can auto-initialize on restart
600
+ }))
601
+
602
+ log(`Created new wallet: ${walletId} and set as active`)
603
+ } catch (err) {
604
+ const errorMessage = err instanceof Error ? err.message : String(err)
605
+ logError('Failed to create wallet:', err)
606
+ setWalletListError(errorMessage)
607
+ throw err
608
+ } finally {
609
+ setIsWalletListLoading(false)
610
+ }
611
+ }, [checkWallet])
612
+
613
+ // Memoize return object to prevent unnecessary re-renders
614
+ return useMemo(
615
+ () => ({
616
+ initializeWallet,
617
+ initializeFromMnemonic,
618
+ hasWallet,
619
+ deleteWallet,
620
+ getMnemonic,
621
+ createTemporaryWallet,
622
+ isInitializing, // Derived from walletLoadingState (single source of truth)
623
+ error,
624
+ clearError,
625
+ clearActiveWallet,
626
+ // Wallet list operations
627
+ wallets: walletListState.wallets,
628
+ activeWalletId: walletListState.activeWalletId,
629
+ createWallet,
630
+ refreshWalletList,
631
+ isWalletListLoading,
632
+ walletListError,
633
+ }),
634
+ [
635
+ initializeWallet,
636
+ initializeFromMnemonic,
637
+ hasWallet,
638
+ deleteWallet,
639
+ getMnemonic,
640
+ createTemporaryWallet,
641
+ isInitializing,
642
+ error,
643
+ clearError,
644
+ clearActiveWallet,
645
+ walletListState.wallets,
646
+ walletListState.activeWalletId,
647
+ createWallet,
648
+ refreshWalletList,
649
+ isWalletListLoading,
650
+ walletListError,
651
+ ]
652
+ )
653
+ }
654
+