@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.
- package/README.md +551 -0
- package/dist/__mocks__/react.d.ts +40 -0
- package/dist/__mocks__/react.js +33 -0
- package/dist/__mocks__/react.js.map +1 -0
- package/dist/__mocks__/secureStorage.d.ts +26 -0
- package/dist/__mocks__/secureStorage.js +80 -0
- package/dist/__mocks__/secureStorage.js.map +1 -0
- package/dist/__tests__/hooks/useBalance.test.d.ts +6 -0
- package/dist/__tests__/hooks/useBalance.test.js +217 -0
- package/dist/__tests__/hooks/useBalance.test.js.map +1 -0
- package/dist/__tests__/hooks/useWallet.test.d.ts +6 -0
- package/dist/__tests__/hooks/useWallet.test.js +105 -0
- package/dist/__tests__/hooks/useWallet.test.js.map +1 -0
- package/dist/__tests__/hooks/useWalletManager.test.d.ts +6 -0
- package/dist/__tests__/hooks/useWalletManager.test.js +193 -0
- package/dist/__tests__/hooks/useWalletManager.test.js.map +1 -0
- package/dist/__tests__/hooks/useWdkApp.test.d.ts +6 -0
- package/dist/__tests__/hooks/useWdkApp.test.js +55 -0
- package/dist/__tests__/hooks/useWdkApp.test.js.map +1 -0
- package/dist/__tests__/hooks/useWorklet.test.d.ts +6 -0
- package/dist/__tests__/hooks/useWorklet.test.js +168 -0
- package/dist/__tests__/hooks/useWorklet.test.js.map +1 -0
- package/dist/__tests__/provider/WdkAppProvider.test.d.ts +6 -0
- package/dist/__tests__/provider/WdkAppProvider.test.js +57 -0
- package/dist/__tests__/provider/WdkAppProvider.test.js.map +1 -0
- package/dist/__tests__/services/accountService.test.d.ts +6 -0
- package/dist/__tests__/services/accountService.test.js +216 -0
- package/dist/__tests__/services/accountService.test.js.map +1 -0
- package/dist/__tests__/services/addressService.test.d.ts +6 -0
- package/dist/__tests__/services/addressService.test.js +246 -0
- package/dist/__tests__/services/addressService.test.js.map +1 -0
- package/dist/__tests__/services/balanceService.test.d.ts +6 -0
- package/dist/__tests__/services/balanceService.test.js +333 -0
- package/dist/__tests__/services/balanceService.test.js.map +1 -0
- package/dist/__tests__/services/walletSetupService.test.d.ts +6 -0
- package/dist/__tests__/services/walletSetupService.test.js +304 -0
- package/dist/__tests__/services/walletSetupService.test.js.map +1 -0
- package/dist/__tests__/services/walletSwitchingService.test.d.ts +6 -0
- package/dist/__tests__/services/walletSwitchingService.test.js +209 -0
- package/dist/__tests__/services/walletSwitchingService.test.js.map +1 -0
- package/dist/__tests__/services/workletLifecycleService.test.d.ts +6 -0
- package/dist/__tests__/services/workletLifecycleService.test.js +451 -0
- package/dist/__tests__/services/workletLifecycleService.test.js.map +1 -0
- package/dist/__tests__/setup.d.ts +7 -0
- package/dist/__tests__/setup.js +49 -0
- package/dist/__tests__/setup.js.map +1 -0
- package/dist/__tests__/storage/mmkvStorage.test.d.ts +6 -0
- package/dist/__tests__/storage/mmkvStorage.test.js +213 -0
- package/dist/__tests__/storage/mmkvStorage.test.js.map +1 -0
- package/dist/__tests__/store/walletStore.test.d.ts +4 -0
- package/dist/__tests__/store/walletStore.test.js +86 -0
- package/dist/__tests__/store/walletStore.test.js.map +1 -0
- package/dist/__tests__/store/workletStore.test.d.ts +4 -0
- package/dist/__tests__/store/workletStore.test.js +255 -0
- package/dist/__tests__/store/workletStore.test.js.map +1 -0
- package/dist/__tests__/types/hrpc.test.d.ts +4 -0
- package/dist/__tests__/types/hrpc.test.js +99 -0
- package/dist/__tests__/types/hrpc.test.js.map +1 -0
- package/dist/__tests__/utils/balanceUtils.test.d.ts +4 -0
- package/dist/__tests__/utils/balanceUtils.test.js +133 -0
- package/dist/__tests__/utils/balanceUtils.test.js.map +1 -0
- package/dist/__tests__/utils/errorHandling.test.d.ts +6 -0
- package/dist/__tests__/utils/errorHandling.test.js +119 -0
- package/dist/__tests__/utils/errorHandling.test.js.map +1 -0
- package/dist/__tests__/utils/errorUtils.test.d.ts +4 -0
- package/dist/__tests__/utils/errorUtils.test.js +133 -0
- package/dist/__tests__/utils/errorUtils.test.js.map +1 -0
- package/dist/__tests__/utils/initializationState.test.d.ts +6 -0
- package/dist/__tests__/utils/initializationState.test.js +243 -0
- package/dist/__tests__/utils/initializationState.test.js.map +1 -0
- package/dist/__tests__/utils/jsonUtils.test.d.ts +4 -0
- package/dist/__tests__/utils/jsonUtils.test.js +118 -0
- package/dist/__tests__/utils/jsonUtils.test.js.map +1 -0
- package/dist/__tests__/utils/mmkvKeyManager.test.d.ts +6 -0
- package/dist/__tests__/utils/mmkvKeyManager.test.js +158 -0
- package/dist/__tests__/utils/mmkvKeyManager.test.js.map +1 -0
- package/dist/__tests__/utils/mnemonicUtils.test.d.ts +4 -0
- package/dist/__tests__/utils/mnemonicUtils.test.js +40 -0
- package/dist/__tests__/utils/mnemonicUtils.test.js.map +1 -0
- package/dist/__tests__/utils/raceConditions.test.d.ts +6 -0
- package/dist/__tests__/utils/raceConditions.test.js +239 -0
- package/dist/__tests__/utils/raceConditions.test.js.map +1 -0
- package/dist/__tests__/utils/result.test.d.ts +4 -0
- package/dist/__tests__/utils/result.test.js +66 -0
- package/dist/__tests__/utils/result.test.js.map +1 -0
- package/dist/__tests__/utils/schemas.test.d.ts +4 -0
- package/dist/__tests__/utils/schemas.test.js +66 -0
- package/dist/__tests__/utils/schemas.test.js.map +1 -0
- package/dist/__tests__/utils/storeHelpers.test.d.ts +4 -0
- package/dist/__tests__/utils/storeHelpers.test.js +227 -0
- package/dist/__tests__/utils/storeHelpers.test.js.map +1 -0
- package/dist/__tests__/utils/typeGuards.test.d.ts +4 -0
- package/dist/__tests__/utils/typeGuards.test.js +175 -0
- package/dist/__tests__/utils/typeGuards.test.js.map +1 -0
- package/dist/__tests__/utils/validation.test.d.ts +4 -0
- package/dist/__tests__/utils/validation.test.js +126 -0
- package/dist/__tests__/utils/validation.test.js.map +1 -0
- package/dist/__tests__/utils/walletUtils.test.d.ts +4 -0
- package/dist/__tests__/utils/walletUtils.test.js +156 -0
- package/dist/__tests__/utils/walletUtils.test.js.map +1 -0
- package/dist/hooks/useBalance.d.ts +170 -0
- package/dist/hooks/useBalance.js +442 -0
- package/dist/hooks/useBalance.js.map +1 -0
- package/dist/hooks/useWallet.d.ts +43 -0
- package/dist/hooks/useWallet.js +193 -0
- package/dist/hooks/useWallet.js.map +1 -0
- package/dist/hooks/useWalletManager.d.ts +100 -0
- package/dist/hooks/useWalletManager.js +526 -0
- package/dist/hooks/useWalletManager.js.map +1 -0
- package/dist/hooks/useWdkApp.d.ts +66 -0
- package/dist/hooks/useWdkApp.js +74 -0
- package/dist/hooks/useWdkApp.js.map +1 -0
- package/dist/hooks/useWorklet.d.ts +66 -0
- package/dist/hooks/useWorklet.js +42 -0
- package/dist/hooks/useWorklet.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -0
- package/dist/provider/WdkAppProvider.d.ts +112 -0
- package/dist/provider/WdkAppProvider.js +558 -0
- package/dist/provider/WdkAppProvider.js.map +1 -0
- package/dist/services/accountService.d.ts +52 -0
- package/dist/services/accountService.js +119 -0
- package/dist/services/accountService.js.map +1 -0
- package/dist/services/addressService.d.ts +22 -0
- package/dist/services/addressService.js +110 -0
- package/dist/services/addressService.js.map +1 -0
- package/dist/services/balanceService.d.ts +114 -0
- package/dist/services/balanceService.js +208 -0
- package/dist/services/balanceService.js.map +1 -0
- package/dist/services/walletSetupService.d.ts +217 -0
- package/dist/services/walletSetupService.js +535 -0
- package/dist/services/walletSetupService.js.map +1 -0
- package/dist/services/walletSwitchingService.d.ts +48 -0
- package/dist/services/walletSwitchingService.js +143 -0
- package/dist/services/walletSwitchingService.js.map +1 -0
- package/dist/services/workletLifecycleService.d.ts +117 -0
- package/dist/services/workletLifecycleService.js +433 -0
- package/dist/services/workletLifecycleService.js.map +1 -0
- package/dist/storage/mmkvStorage.d.ts +44 -0
- package/dist/storage/mmkvStorage.js +348 -0
- package/dist/storage/mmkvStorage.js.map +1 -0
- package/dist/store/walletStore.d.ts +130 -0
- package/dist/store/walletStore.js +204 -0
- package/dist/store/walletStore.js.map +1 -0
- package/dist/store/workletStore.d.ts +121 -0
- package/dist/store/workletStore.js +256 -0
- package/dist/store/workletStore.js.map +1 -0
- package/dist/types/hrpc.d.ts +60 -0
- package/dist/types/hrpc.js +26 -0
- package/dist/types/hrpc.js.map +1 -0
- package/dist/types.d.ts +168 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/balanceUtils.d.ts +30 -0
- package/dist/utils/balanceUtils.js +86 -0
- package/dist/utils/balanceUtils.js.map +1 -0
- package/dist/utils/constants.d.ts +66 -0
- package/dist/utils/constants.js +73 -0
- package/dist/utils/constants.js.map +1 -0
- package/dist/utils/errorHandling.d.ts +47 -0
- package/dist/utils/errorHandling.js +54 -0
- package/dist/utils/errorHandling.js.map +1 -0
- package/dist/utils/errorUtils.d.ts +89 -0
- package/dist/utils/errorUtils.js +264 -0
- package/dist/utils/errorUtils.js.map +1 -0
- package/dist/utils/initializationState.d.ts +129 -0
- package/dist/utils/initializationState.js +220 -0
- package/dist/utils/initializationState.js.map +1 -0
- package/dist/utils/jsonUtils.d.ts +21 -0
- package/dist/utils/jsonUtils.js +67 -0
- package/dist/utils/jsonUtils.js.map +1 -0
- package/dist/utils/logger.d.ts +27 -0
- package/dist/utils/logger.js +50 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/mmkvKeyManager.d.ts +57 -0
- package/dist/utils/mmkvKeyManager.js +214 -0
- package/dist/utils/mmkvKeyManager.js.map +1 -0
- package/dist/utils/mnemonicUtils.d.ts +17 -0
- package/dist/utils/mnemonicUtils.js +28 -0
- package/dist/utils/mnemonicUtils.js.map +1 -0
- package/dist/utils/operationMutex.d.ts +69 -0
- package/dist/utils/operationMutex.js +150 -0
- package/dist/utils/operationMutex.js.map +1 -0
- package/dist/utils/result.d.ts +34 -0
- package/dist/utils/result.js +43 -0
- package/dist/utils/result.js.map +1 -0
- package/dist/utils/schemas.d.ts +365 -0
- package/dist/utils/schemas.js +152 -0
- package/dist/utils/schemas.js.map +1 -0
- package/dist/utils/storeHelpers.d.ts +112 -0
- package/dist/utils/storeHelpers.js +198 -0
- package/dist/utils/storeHelpers.js.map +1 -0
- package/dist/utils/typeGuards.d.ts +70 -0
- package/dist/utils/typeGuards.js +95 -0
- package/dist/utils/typeGuards.js.map +1 -0
- package/dist/utils/validation.d.ts +53 -0
- package/dist/utils/validation.js +152 -0
- package/dist/utils/validation.js.map +1 -0
- package/dist/utils/walletStateHelpers.d.ts +62 -0
- package/dist/utils/walletStateHelpers.js +81 -0
- package/dist/utils/walletStateHelpers.js.map +1 -0
- package/dist/utils/walletUtils.d.ts +38 -0
- package/dist/utils/walletUtils.js +87 -0
- package/dist/utils/walletUtils.js.map +1 -0
- package/package.json +79 -0
- package/src/__mocks__/react.ts +34 -0
- package/src/__mocks__/secureStorage.ts +87 -0
- package/src/__tests__/hooks/useBalance.test.ts +286 -0
- package/src/__tests__/hooks/useWallet.test.ts +122 -0
- package/src/__tests__/hooks/useWalletManager.test.ts +271 -0
- package/src/__tests__/hooks/useWdkApp.test.tsx +59 -0
- package/src/__tests__/hooks/useWorklet.test.ts +195 -0
- package/src/__tests__/provider/WdkAppProvider.test.tsx +67 -0
- package/src/__tests__/services/accountService.test.ts +337 -0
- package/src/__tests__/services/addressService.test.ts +312 -0
- package/src/__tests__/services/balanceService.test.ts +411 -0
- package/src/__tests__/services/walletSetupService.test.ts +463 -0
- package/src/__tests__/services/walletSwitchingService.test.ts +258 -0
- package/src/__tests__/services/workletLifecycleService.test.ts +514 -0
- package/src/__tests__/setup.ts +54 -0
- package/src/__tests__/storage/mmkvStorage.test.ts +325 -0
- package/src/__tests__/store/walletStore.test.ts +101 -0
- package/src/__tests__/store/workletStore.test.ts +329 -0
- package/src/__tests__/types/hrpc.test.ts +125 -0
- package/src/__tests__/utils/balanceUtils.test.ts +151 -0
- package/src/__tests__/utils/errorHandling.test.ts +147 -0
- package/src/__tests__/utils/errorUtils.test.ts +170 -0
- package/src/__tests__/utils/initializationState.test.ts +337 -0
- package/src/__tests__/utils/jsonUtils.test.ts +131 -0
- package/src/__tests__/utils/mmkvKeyManager.test.ts +205 -0
- package/src/__tests__/utils/mnemonicUtils.test.ts +48 -0
- package/src/__tests__/utils/raceConditions.test.ts +292 -0
- package/src/__tests__/utils/result.test.ts +73 -0
- package/src/__tests__/utils/schemas.test.ts +82 -0
- package/src/__tests__/utils/storeHelpers.test.ts +323 -0
- package/src/__tests__/utils/typeGuards.test.ts +209 -0
- package/src/__tests__/utils/validation.test.ts +152 -0
- package/src/__tests__/utils/walletUtils.test.ts +195 -0
- package/src/hooks/useBalance.ts +597 -0
- package/src/hooks/useWallet.ts +288 -0
- package/src/hooks/useWalletManager.ts +654 -0
- package/src/hooks/useWdkApp.ts +78 -0
- package/src/hooks/useWorklet.ts +109 -0
- package/src/index.ts +112 -0
- package/src/provider/WdkAppProvider.tsx +764 -0
- package/src/services/accountService.ts +134 -0
- package/src/services/addressService.ts +125 -0
- package/src/services/balanceService.ts +291 -0
- package/src/services/walletSetupService.ts +695 -0
- package/src/services/walletSwitchingService.ts +157 -0
- package/src/services/workletLifecycleService.ts +561 -0
- package/src/storage/mmkvStorage.ts +417 -0
- package/src/store/walletStore.ts +301 -0
- package/src/store/workletStore.ts +340 -0
- package/src/types/hrpc.ts +78 -0
- package/src/types.ts +188 -0
- package/src/utils/balanceUtils.ts +96 -0
- package/src/utils/constants.ts +84 -0
- package/src/utils/errorHandling.md +163 -0
- package/src/utils/errorHandling.ts +61 -0
- package/src/utils/errorUtils.ts +300 -0
- package/src/utils/initializationState.ts +242 -0
- package/src/utils/jsonUtils.ts +75 -0
- package/src/utils/logger.ts +54 -0
- package/src/utils/mmkvKeyManager.ts +256 -0
- package/src/utils/mnemonicUtils.ts +35 -0
- package/src/utils/operationMutex.ts +181 -0
- package/src/utils/result.ts +57 -0
- package/src/utils/schemas.ts +190 -0
- package/src/utils/storeHelpers.ts +236 -0
- package/src/utils/typeGuards.ts +129 -0
- package/src/utils/validation.ts +174 -0
- package/src/utils/walletStateHelpers.ts +104 -0
- package/src/utils/walletUtils.ts +107 -0
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wallet Store - Source of Truth for Wallet Data
|
|
3
|
+
*
|
|
4
|
+
* IMPORTANT: This is the ONLY place where addresses and balances are actually stored.
|
|
5
|
+
*
|
|
6
|
+
* ## Store Boundaries
|
|
7
|
+
*
|
|
8
|
+
* **walletStore** (this file):
|
|
9
|
+
* - Wallet addresses: { [walletId]: { [network]: { [accountIndex]: address } } }
|
|
10
|
+
* - Wallet balances: { [walletId]: { [network]: { [accountIndex]: { [tokenAddress]: balance } } } }
|
|
11
|
+
* - Address loading states: { [walletId]: { [network-accountIndex]: boolean } }
|
|
12
|
+
* - Balance loading states: { [walletId]: { [network-accountIndex-tokenAddress]: boolean } }
|
|
13
|
+
* - Last balance update timestamps: { [walletId]: { [network]: { [accountIndex]: timestamp } } }
|
|
14
|
+
* - Account list: { [walletId]: Array of account info }
|
|
15
|
+
* - Wallet list: Array of wallet info (multiple wallets)
|
|
16
|
+
* - Active wallet ID: Currently active wallet identifier
|
|
17
|
+
*
|
|
18
|
+
* Note: Loading states for wallet list operations are managed locally in hooks
|
|
19
|
+
* (useWalletManager) since they're ephemeral and only used within those hooks.
|
|
20
|
+
*
|
|
21
|
+
* **workletStore** (workletStore.ts):
|
|
22
|
+
* - Worklet lifecycle state (isWorkletStarted, isInitialized, etc.)
|
|
23
|
+
* - Worklet runtime instances (worklet, hrpc, ipc)
|
|
24
|
+
* - Worklet configuration
|
|
25
|
+
*
|
|
26
|
+
* ## Separation of Concerns
|
|
27
|
+
*
|
|
28
|
+
* - **walletStore**: Manages wallet data (addresses, balances) - derived/computed from worklet
|
|
29
|
+
* - **workletStore**: Manages worklet runtime and lifecycle
|
|
30
|
+
*
|
|
31
|
+
* These stores are intentionally separate to:
|
|
32
|
+
* 1. Prevent cross-contamination of lifecycle and data concerns
|
|
33
|
+
* 2. Allow independent persistence strategies
|
|
34
|
+
* 3. Enable clear boundaries for testing and debugging
|
|
35
|
+
*
|
|
36
|
+
* ## Important Notes
|
|
37
|
+
*
|
|
38
|
+
* - Addresses: Stored in Zustand (derived/computed state, deterministic, no refetching needed)
|
|
39
|
+
* - Balances: Stored in Zustand (single source of truth), use TanStack Query via useBalance() hook for fetching
|
|
40
|
+
* - Zustand is the single source of truth for balances
|
|
41
|
+
* - TanStack Query reads from Zustand (initialData) and updates Zustand after fetch
|
|
42
|
+
* - No sync logic needed - TanStack Query directly updates the source of truth
|
|
43
|
+
* - NEVER store worklet lifecycle state in walletStore
|
|
44
|
+
* - NEVER store worklet runtime instances in walletStore
|
|
45
|
+
* - All operations are handled by focused services (AddressService, BalanceService), not the store itself
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
// External packages
|
|
49
|
+
import { create } from 'zustand'
|
|
50
|
+
import { persist, createJSONStorage, devtools } from 'zustand/middleware'
|
|
51
|
+
|
|
52
|
+
// Local imports
|
|
53
|
+
import type {
|
|
54
|
+
WalletAddressesByWallet,
|
|
55
|
+
WalletBalancesByWallet,
|
|
56
|
+
BalanceLoadingStates,
|
|
57
|
+
} from '../types'
|
|
58
|
+
import { createMMKVStorageAdapter } from '../storage/mmkvStorage'
|
|
59
|
+
import { log, logError } from '../utils/logger'
|
|
60
|
+
|
|
61
|
+
export interface WalletLoadingStates {
|
|
62
|
+
[key: string]: boolean
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface AccountInfo {
|
|
66
|
+
/** Account index (0-based) */
|
|
67
|
+
accountIndex: number
|
|
68
|
+
/** Account address for each network */
|
|
69
|
+
addresses: Record<string, string>
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface WalletInfo {
|
|
73
|
+
/** Wallet identifier (e.g., user email) */
|
|
74
|
+
identifier: string
|
|
75
|
+
/** Whether wallet exists in secure storage */
|
|
76
|
+
exists: boolean
|
|
77
|
+
/** Whether this wallet is currently active/initialized */
|
|
78
|
+
isActive: boolean
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Wallet loading state - tracks the lifecycle of loading a specific wallet
|
|
83
|
+
* This is the single source of truth for wallet loading state
|
|
84
|
+
*/
|
|
85
|
+
export type WalletLoadingState =
|
|
86
|
+
| { type: 'not_loaded' }
|
|
87
|
+
| { type: 'checking'; identifier: string }
|
|
88
|
+
| { type: 'loading'; identifier: string; walletExists: boolean }
|
|
89
|
+
| { type: 'ready'; identifier: string }
|
|
90
|
+
| { type: 'error'; identifier: string | null; error: Error }
|
|
91
|
+
|
|
92
|
+
export interface WalletState {
|
|
93
|
+
// SOURCE OF TRUTH - addresses stored ONLY here (per-wallet)
|
|
94
|
+
addresses: WalletAddressesByWallet // walletId -> addresses
|
|
95
|
+
walletLoading: Record<string, WalletLoadingStates> // walletId -> loading states
|
|
96
|
+
// SOURCE OF TRUTH - balances stored ONLY here (per-wallet)
|
|
97
|
+
balances: WalletBalancesByWallet // walletId -> balances
|
|
98
|
+
// Maps walletId -> "network-accountIndex-tokenAddress" -> boolean
|
|
99
|
+
balanceLoading: Record<string, BalanceLoadingStates> // walletId -> loading states
|
|
100
|
+
lastBalanceUpdate: Record<string, Record<string, Record<number, number>>> // walletId -> network -> accountIndex -> timestamp
|
|
101
|
+
// Account list management (per-wallet)
|
|
102
|
+
accountList: Record<string, AccountInfo[]> // walletId -> account list
|
|
103
|
+
// Wallet list management
|
|
104
|
+
walletList: WalletInfo[]
|
|
105
|
+
activeWalletId: string | null
|
|
106
|
+
// SOURCE OF TRUTH - wallet loading state (replaces React reducer)
|
|
107
|
+
walletLoadingState: WalletLoadingState
|
|
108
|
+
// Operation mutex - prevents concurrent wallet operations
|
|
109
|
+
isOperationInProgress: boolean
|
|
110
|
+
currentOperation: string | null // Description of current operation
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export type WalletStore = WalletState
|
|
114
|
+
|
|
115
|
+
type WalletStoreInstance = ReturnType<ReturnType<typeof create<WalletStore>>>
|
|
116
|
+
|
|
117
|
+
const initialState: WalletState = {
|
|
118
|
+
addresses: {}, // walletId -> addresses
|
|
119
|
+
walletLoading: {}, // walletId -> loading states
|
|
120
|
+
balances: {}, // walletId -> balances
|
|
121
|
+
balanceLoading: {}, // walletId -> loading states
|
|
122
|
+
lastBalanceUpdate: {}, // walletId -> network -> accountIndex -> timestamp
|
|
123
|
+
accountList: {}, // walletId -> account list
|
|
124
|
+
walletList: [],
|
|
125
|
+
activeWalletId: null,
|
|
126
|
+
walletLoadingState: { type: 'not_loaded' },
|
|
127
|
+
isOperationInProgress: false,
|
|
128
|
+
currentOperation: null,
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const defaultStorageAdapter = createMMKVStorageAdapter()
|
|
132
|
+
|
|
133
|
+
let walletStoreInstance: WalletStoreInstance | null = null
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Creates singleton wallet store instance.
|
|
137
|
+
* All operations are handled by focused services (AddressService, BalanceService), not the store itself.
|
|
138
|
+
*/
|
|
139
|
+
export function createWalletStore(): WalletStoreInstance {
|
|
140
|
+
if (walletStoreInstance) {
|
|
141
|
+
return walletStoreInstance
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const store = create<WalletStore>()(
|
|
145
|
+
devtools(
|
|
146
|
+
persist(
|
|
147
|
+
(set, get) => ({
|
|
148
|
+
...initialState,
|
|
149
|
+
}),
|
|
150
|
+
{
|
|
151
|
+
name: 'wallet-storage',
|
|
152
|
+
storage: createJSONStorage(() => defaultStorageAdapter),
|
|
153
|
+
partialize: (state: WalletState) => ({
|
|
154
|
+
addresses: state.addresses,
|
|
155
|
+
balances: state.balances,
|
|
156
|
+
balanceLoading: {},
|
|
157
|
+
lastBalanceUpdate: state.lastBalanceUpdate,
|
|
158
|
+
accountList: state.accountList,
|
|
159
|
+
walletList: state.walletList,
|
|
160
|
+
activeWalletId: state.activeWalletId,
|
|
161
|
+
// Don't persist loading state or operation mutex - these are runtime-only
|
|
162
|
+
}),
|
|
163
|
+
onRehydrateStorage: () => {
|
|
164
|
+
return (state: WalletState | undefined) => {
|
|
165
|
+
if (state) {
|
|
166
|
+
log('🔄 Rehydrating wallet state - resetting loading states')
|
|
167
|
+
state.walletLoading = {}
|
|
168
|
+
state.balanceLoading = {}
|
|
169
|
+
// Reset runtime-only state
|
|
170
|
+
state.walletLoadingState = { type: 'not_loaded' }
|
|
171
|
+
state.isOperationInProgress = false
|
|
172
|
+
state.currentOperation = null
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
}
|
|
177
|
+
),
|
|
178
|
+
{ name: 'WalletStore' }
|
|
179
|
+
)
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
walletStoreInstance = store
|
|
183
|
+
return store
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export function getWalletStore() {
|
|
187
|
+
return createWalletStore()
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Wallet state actions - helper functions for updating wallet loading state
|
|
192
|
+
* These provide a clean API for state transitions with validation
|
|
193
|
+
*/
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Validate state transition
|
|
197
|
+
* Returns true if transition is valid, false otherwise
|
|
198
|
+
*/
|
|
199
|
+
function isValidStateTransition(
|
|
200
|
+
current: WalletLoadingState,
|
|
201
|
+
next: WalletLoadingState['type']
|
|
202
|
+
): boolean {
|
|
203
|
+
// Allow reset from any state
|
|
204
|
+
if (next === 'not_loaded') return true
|
|
205
|
+
|
|
206
|
+
// Allow error from any state
|
|
207
|
+
if (next === 'error') return true
|
|
208
|
+
|
|
209
|
+
// After early returns, TypeScript narrows the type, but we need to check all transitions
|
|
210
|
+
// Use type assertion to tell TypeScript that 'not_loaded' and 'error' are still possible
|
|
211
|
+
// (even though they're handled by early returns, they're valid from all states)
|
|
212
|
+
const nextType = next as WalletLoadingState['type']
|
|
213
|
+
|
|
214
|
+
switch (current.type) {
|
|
215
|
+
case 'not_loaded':
|
|
216
|
+
return nextType === 'checking' || nextType === 'loading'
|
|
217
|
+
case 'checking':
|
|
218
|
+
return nextType === 'loading' || nextType === 'error'
|
|
219
|
+
case 'loading':
|
|
220
|
+
return nextType === 'ready' || nextType === 'error'
|
|
221
|
+
case 'ready':
|
|
222
|
+
return nextType === 'not_loaded' || nextType === 'loading' || nextType === 'checking'
|
|
223
|
+
case 'error':
|
|
224
|
+
return nextType === 'not_loaded' || nextType === 'checking' || nextType === 'loading'
|
|
225
|
+
default:
|
|
226
|
+
return false
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Update wallet loading state with validation
|
|
232
|
+
* Throws error if transition is invalid
|
|
233
|
+
* Logs state transitions for debugging
|
|
234
|
+
*/
|
|
235
|
+
export function updateWalletLoadingState(
|
|
236
|
+
state: WalletState,
|
|
237
|
+
newState: WalletLoadingState
|
|
238
|
+
): Partial<WalletState> {
|
|
239
|
+
// Log state transition for debugging
|
|
240
|
+
if (state.walletLoadingState.type !== newState.type) {
|
|
241
|
+
log(`[WalletState] Transition: ${state.walletLoadingState.type} -> ${newState.type}`, {
|
|
242
|
+
from: state.walletLoadingState,
|
|
243
|
+
to: newState,
|
|
244
|
+
})
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (!isValidStateTransition(state.walletLoadingState, newState.type)) {
|
|
248
|
+
const error = new Error(
|
|
249
|
+
`Invalid state transition from ${state.walletLoadingState.type} to ${newState.type}`
|
|
250
|
+
)
|
|
251
|
+
logError(`⚠️ Invalid state transition: ${error.message}`, {
|
|
252
|
+
currentState: state.walletLoadingState,
|
|
253
|
+
attemptedState: newState,
|
|
254
|
+
})
|
|
255
|
+
// In development, throw error. In production, log and allow transition
|
|
256
|
+
// Note: __DEV__ is a React Native global, may not be available in all environments
|
|
257
|
+
if (typeof __DEV__ !== 'undefined' && __DEV__) {
|
|
258
|
+
throw error
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return { walletLoadingState: newState }
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Get wallet identifier from loading state
|
|
267
|
+
*/
|
|
268
|
+
export function getWalletIdFromLoadingState(state: WalletLoadingState): string | null {
|
|
269
|
+
switch (state.type) {
|
|
270
|
+
case 'checking':
|
|
271
|
+
case 'loading':
|
|
272
|
+
case 'ready':
|
|
273
|
+
return state.identifier
|
|
274
|
+
case 'error':
|
|
275
|
+
return state.identifier
|
|
276
|
+
case 'not_loaded':
|
|
277
|
+
return null
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Check if wallet is in a loading state
|
|
283
|
+
*/
|
|
284
|
+
export function isWalletLoadingState(state: WalletLoadingState): boolean {
|
|
285
|
+
return state.type === 'checking' || state.type === 'loading'
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Check if wallet is ready
|
|
290
|
+
*/
|
|
291
|
+
export function isWalletReadyState(state: WalletLoadingState): boolean {
|
|
292
|
+
return state.type === 'ready'
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Check if wallet is in error state
|
|
297
|
+
*/
|
|
298
|
+
export function isWalletErrorState(state: WalletLoadingState): boolean {
|
|
299
|
+
return state.type === 'error'
|
|
300
|
+
}
|
|
301
|
+
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worklet Store - Source of Truth for Worklet Lifecycle
|
|
3
|
+
*
|
|
4
|
+
* This store manages worklet lifecycle state (initialization, configuration, runtime instances).
|
|
5
|
+
*
|
|
6
|
+
* ## Store Boundaries
|
|
7
|
+
*
|
|
8
|
+
* **workletStore** (this file):
|
|
9
|
+
* - Worklet lifecycle state (isWorkletStarted, isInitialized, isLoading)
|
|
10
|
+
* - Worklet runtime instances (worklet, hrpc, ipc)
|
|
11
|
+
* - Worklet configuration (networkConfigs)
|
|
12
|
+
* - Worklet initialization results (workletStartResult, wdkInitResult)
|
|
13
|
+
* - Encrypted credentials in memory (encryptedSeed, encryptionKey) - for active wallet
|
|
14
|
+
* - Multi-wallet credential cache (credentialsCache) - for multiple wallets
|
|
15
|
+
*
|
|
16
|
+
* **walletStore** (walletStore.ts):
|
|
17
|
+
* - Wallet data (addresses, balances)
|
|
18
|
+
* - Wallet loading states
|
|
19
|
+
* - Balance loading states
|
|
20
|
+
* - Last balance update timestamps
|
|
21
|
+
*
|
|
22
|
+
* ## Separation of Concerns
|
|
23
|
+
*
|
|
24
|
+
* - **workletStore**: Manages the worklet runtime and its lifecycle
|
|
25
|
+
* - **walletStore**: Manages wallet data derived from the worklet
|
|
26
|
+
*
|
|
27
|
+
* These stores are intentionally separate to:
|
|
28
|
+
* 1. Prevent cross-contamination of lifecycle and data concerns
|
|
29
|
+
* 2. Allow independent persistence strategies
|
|
30
|
+
* 3. Enable clear boundaries for testing and debugging
|
|
31
|
+
*
|
|
32
|
+
* ## Important Notes
|
|
33
|
+
*
|
|
34
|
+
* - NEVER store wallet data (addresses, balances) in workletStore
|
|
35
|
+
* - NEVER store worklet lifecycle state in walletStore
|
|
36
|
+
* - All worklet state is runtime-only - state resets completely on app restart
|
|
37
|
+
* - Worklets must be recreated when the app restarts
|
|
38
|
+
* - Encrypted credentials are runtime-only (loaded from secure storage when needed)
|
|
39
|
+
* - All operations are handled by WorkletLifecycleService, not the store itself
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
// External packages
|
|
43
|
+
import { create } from 'zustand'
|
|
44
|
+
import { devtools } from 'zustand/middleware'
|
|
45
|
+
import { Worklet } from '@spacesops/react-native-bare-kit'
|
|
46
|
+
import { HRPC } from '@spacesops/pear-wrk-wdk'
|
|
47
|
+
import type { WorkletStartResponse } from '@spacesops/pear-wrk-wdk/types/rpc'
|
|
48
|
+
|
|
49
|
+
// Local imports
|
|
50
|
+
import type {
|
|
51
|
+
NetworkConfigs,
|
|
52
|
+
} from '../types'
|
|
53
|
+
import { log } from '../utils/logger'
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Maximum number of credentials to cache before evicting least recently used
|
|
57
|
+
* This prevents unbounded memory growth while maintaining performance
|
|
58
|
+
* Recommended: 10-20 wallets for typical use cases
|
|
59
|
+
*
|
|
60
|
+
* Cache Management:
|
|
61
|
+
* - Size Limit: When cache exceeds MAX_CREDENTIALS_CACHE_SIZE, LRU entries are evicted
|
|
62
|
+
* - TTL (Time To Live): Each credential has an expiration timestamp (default: 5 minutes)
|
|
63
|
+
* - Automatic Expiration: Expired credentials are removed on access
|
|
64
|
+
* - LRU Eviction: Least recently used credentials are evicted when size limit is reached
|
|
65
|
+
*
|
|
66
|
+
* These safeguards ensure:
|
|
67
|
+
* 1. Memory usage remains bounded
|
|
68
|
+
* 2. Credentials don't persist indefinitely in memory
|
|
69
|
+
* 3. Frequently used wallets remain cached for better UX
|
|
70
|
+
*/
|
|
71
|
+
const MAX_CREDENTIALS_CACHE_SIZE = 15
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Cached credentials interface for multi-wallet support
|
|
75
|
+
* Credentials are cached in workletStore to avoid repeated biometric prompts
|
|
76
|
+
*/
|
|
77
|
+
export interface CachedCredentials {
|
|
78
|
+
encryptionKey?: string
|
|
79
|
+
encryptedSeed?: string
|
|
80
|
+
encryptedEntropy?: string
|
|
81
|
+
expiresAt: number // TTL timestamp
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Access tracking for LRU eviction
|
|
86
|
+
* Tracks when each credential was last accessed
|
|
87
|
+
*/
|
|
88
|
+
const credentialsAccessOrder = new Map<string, number>()
|
|
89
|
+
let credentialsAccessCounter = 0
|
|
90
|
+
|
|
91
|
+
export interface WorkletState {
|
|
92
|
+
worklet: Worklet | null
|
|
93
|
+
hrpc: HRPC | null
|
|
94
|
+
ipc: unknown | null
|
|
95
|
+
isWorkletStarted: boolean
|
|
96
|
+
isInitialized: boolean
|
|
97
|
+
isLoading: boolean
|
|
98
|
+
error: string | null
|
|
99
|
+
encryptedSeed: string | null
|
|
100
|
+
encryptionKey: string | null
|
|
101
|
+
// seedPhrase is never stored - we only use encrypted approach
|
|
102
|
+
// encryptedEntropy is stored in secure storage but not in runtime state
|
|
103
|
+
// It's only needed when retrieving mnemonic, so it's loaded from secure storage on demand
|
|
104
|
+
networkConfigs: NetworkConfigs | null
|
|
105
|
+
workletStartResult: WorkletStartResponse | null
|
|
106
|
+
wdkInitResult: { status?: string | null } | null
|
|
107
|
+
// Multi-wallet credential cache (replaces static Map in WalletSetupService)
|
|
108
|
+
// Each entry has a TTL (expiresAt timestamp) and is automatically evicted when:
|
|
109
|
+
// 1. Cache size exceeds MAX_CREDENTIALS_CACHE_SIZE (LRU eviction)
|
|
110
|
+
// 2. Credential is accessed after expiration (automatic cleanup)
|
|
111
|
+
credentialsCache: Record<string, CachedCredentials>
|
|
112
|
+
// Cache TTL configuration (time to live in milliseconds)
|
|
113
|
+
// Default: 5 minutes - credentials expire after this time
|
|
114
|
+
credentialsCacheTTL: number
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export type WorkletStore = WorkletState
|
|
118
|
+
|
|
119
|
+
type WorkletStoreInstance = ReturnType<ReturnType<typeof create<WorkletStore>>>
|
|
120
|
+
|
|
121
|
+
const initialState: WorkletState = {
|
|
122
|
+
worklet: null,
|
|
123
|
+
hrpc: null,
|
|
124
|
+
ipc: null,
|
|
125
|
+
isWorkletStarted: false,
|
|
126
|
+
isInitialized: false,
|
|
127
|
+
isLoading: false,
|
|
128
|
+
error: null,
|
|
129
|
+
encryptedSeed: null,
|
|
130
|
+
encryptionKey: null,
|
|
131
|
+
networkConfigs: null,
|
|
132
|
+
workletStartResult: null,
|
|
133
|
+
wdkInitResult: null,
|
|
134
|
+
credentialsCache: {},
|
|
135
|
+
credentialsCacheTTL: 5 * 60 * 1000, // 5 minutes
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
let workletStoreInstance: WorkletStoreInstance | null = null
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Creates singleton worklet store instance.
|
|
142
|
+
*
|
|
143
|
+
* This store is runtime-only - all state resets on app restart.
|
|
144
|
+
* All operations are handled by WorkletLifecycleService, not the store itself.
|
|
145
|
+
*/
|
|
146
|
+
export function createWorkletStore(): WorkletStoreInstance {
|
|
147
|
+
if (workletStoreInstance) {
|
|
148
|
+
return workletStoreInstance
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const store = create<WorkletStore>()(
|
|
152
|
+
devtools(
|
|
153
|
+
() => ({
|
|
154
|
+
...initialState,
|
|
155
|
+
}),
|
|
156
|
+
{ name: 'WorkletStore' }
|
|
157
|
+
)
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
workletStoreInstance = store
|
|
161
|
+
return store
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export function getWorkletStore() {
|
|
165
|
+
return createWorkletStore()
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Evict least recently used credentials from cache when limit is reached
|
|
170
|
+
* Logs eviction for monitoring
|
|
171
|
+
*/
|
|
172
|
+
function evictLRUCredentials(): void {
|
|
173
|
+
const store = getWorkletStore()
|
|
174
|
+
const state = store.getState()
|
|
175
|
+
const cacheSize = Object.keys(state.credentialsCache).length
|
|
176
|
+
|
|
177
|
+
if (cacheSize < MAX_CREDENTIALS_CACHE_SIZE) {
|
|
178
|
+
return
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Find the least recently used credential
|
|
182
|
+
let oldestIdentifier: string | null = null
|
|
183
|
+
let oldestAccess = Infinity
|
|
184
|
+
|
|
185
|
+
for (const [identifier, accessTime] of credentialsAccessOrder.entries()) {
|
|
186
|
+
if (accessTime < oldestAccess && state.credentialsCache[identifier]) {
|
|
187
|
+
oldestAccess = accessTime
|
|
188
|
+
oldestIdentifier = identifier
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Remove the least recently used credential
|
|
193
|
+
if (oldestIdentifier !== null) {
|
|
194
|
+
const { [oldestIdentifier]: _, ...rest } = state.credentialsCache
|
|
195
|
+
credentialsAccessOrder.delete(oldestIdentifier)
|
|
196
|
+
store.setState({ credentialsCache: rest })
|
|
197
|
+
log(`[WorkletStore] Evicted LRU credentials cache entry: ${oldestIdentifier} (cache size: ${cacheSize}/${MAX_CREDENTIALS_CACHE_SIZE})`)
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Log cache size if it exceeds warning threshold (50% of max)
|
|
203
|
+
* Useful for monitoring cache growth in production
|
|
204
|
+
*/
|
|
205
|
+
function logCacheSizeIfNeeded(cacheSize: number): void {
|
|
206
|
+
const warningThreshold = Math.ceil(MAX_CREDENTIALS_CACHE_SIZE * 0.5)
|
|
207
|
+
if (cacheSize >= warningThreshold) {
|
|
208
|
+
log(`[WorkletStore] Credentials cache size: ${cacheSize}/${MAX_CREDENTIALS_CACHE_SIZE} (${Math.round(cacheSize / MAX_CREDENTIALS_CACHE_SIZE * 100)}% full)`)
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Get cached credentials for a wallet identifier
|
|
214
|
+
* Returns null if not cached or expired
|
|
215
|
+
* Updates access time for LRU tracking
|
|
216
|
+
*/
|
|
217
|
+
export function getCachedCredentials(identifier: string): CachedCredentials | null {
|
|
218
|
+
const store = getWorkletStore()
|
|
219
|
+
const state = store.getState()
|
|
220
|
+
const cached = state.credentialsCache[identifier]
|
|
221
|
+
|
|
222
|
+
if (!cached) return null
|
|
223
|
+
|
|
224
|
+
// Check expiration
|
|
225
|
+
if (Date.now() > cached.expiresAt) {
|
|
226
|
+
// Remove expired entry
|
|
227
|
+
const { [identifier]: _, ...rest } = state.credentialsCache
|
|
228
|
+
credentialsAccessOrder.delete(identifier)
|
|
229
|
+
store.setState({
|
|
230
|
+
credentialsCache: rest,
|
|
231
|
+
})
|
|
232
|
+
return null
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Update access time for LRU tracking
|
|
236
|
+
credentialsAccessCounter++
|
|
237
|
+
credentialsAccessOrder.set(identifier, credentialsAccessCounter)
|
|
238
|
+
|
|
239
|
+
return cached
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Set cached credentials for a wallet identifier
|
|
244
|
+
* Evicts LRU entries if cache size limit is reached
|
|
245
|
+
* Logs cache size for monitoring
|
|
246
|
+
*/
|
|
247
|
+
export function setCachedCredentials(
|
|
248
|
+
identifier: string,
|
|
249
|
+
credentials: Partial<CachedCredentials>
|
|
250
|
+
): void {
|
|
251
|
+
const store = getWorkletStore()
|
|
252
|
+
const state = store.getState()
|
|
253
|
+
const existing = state.credentialsCache[identifier] || {}
|
|
254
|
+
|
|
255
|
+
// Evict LRU credentials if needed before adding new entry
|
|
256
|
+
// Check if we're adding a new entry (not just updating existing)
|
|
257
|
+
const isNewEntry = !state.credentialsCache[identifier]
|
|
258
|
+
if (isNewEntry) {
|
|
259
|
+
evictLRUCredentials()
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Update access time for LRU tracking
|
|
263
|
+
credentialsAccessCounter++
|
|
264
|
+
credentialsAccessOrder.set(identifier, credentialsAccessCounter)
|
|
265
|
+
|
|
266
|
+
store.setState({
|
|
267
|
+
credentialsCache: {
|
|
268
|
+
...state.credentialsCache,
|
|
269
|
+
[identifier]: {
|
|
270
|
+
...existing,
|
|
271
|
+
...credentials,
|
|
272
|
+
expiresAt: Date.now() + state.credentialsCacheTTL,
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
// Log cache size for monitoring (after state update)
|
|
278
|
+
const newCacheSize = Object.keys(store.getState().credentialsCache).length
|
|
279
|
+
logCacheSizeIfNeeded(newCacheSize)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Clear credentials cache for a specific wallet or all wallets
|
|
284
|
+
* Also clears access tracking
|
|
285
|
+
*/
|
|
286
|
+
export function clearCredentialsCache(identifier?: string): void {
|
|
287
|
+
const store = getWorkletStore()
|
|
288
|
+
const state = store.getState()
|
|
289
|
+
|
|
290
|
+
if (identifier) {
|
|
291
|
+
// Clear specific wallet
|
|
292
|
+
const { [identifier]: _, ...rest } = state.credentialsCache
|
|
293
|
+
credentialsAccessOrder.delete(identifier)
|
|
294
|
+
store.setState({ credentialsCache: rest })
|
|
295
|
+
} else {
|
|
296
|
+
// Clear all
|
|
297
|
+
credentialsAccessOrder.clear()
|
|
298
|
+
credentialsAccessCounter = 0
|
|
299
|
+
store.setState({ credentialsCache: {} })
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Clear all sensitive data from memory (active wallet credentials + cache)
|
|
305
|
+
* This should be called when sensitive data is no longer needed
|
|
306
|
+
* to minimize exposure in memory dumps or debugging
|
|
307
|
+
*
|
|
308
|
+
* Note: In JavaScript, we cannot overwrite memory. Setting to null and clearing
|
|
309
|
+
* references allows garbage collection, but the old values may remain in memory
|
|
310
|
+
* until GC runs. This is a JavaScript limitation.
|
|
311
|
+
*/
|
|
312
|
+
export function clearAllSensitiveData(): void {
|
|
313
|
+
const store = getWorkletStore()
|
|
314
|
+
credentialsAccessOrder.clear()
|
|
315
|
+
credentialsAccessCounter = 0
|
|
316
|
+
store.setState({
|
|
317
|
+
encryptedSeed: null,
|
|
318
|
+
encryptionKey: null,
|
|
319
|
+
credentialsCache: {},
|
|
320
|
+
})
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Reset the worklet store instance (useful for testing)
|
|
325
|
+
* Also resets access tracking
|
|
326
|
+
*/
|
|
327
|
+
export function resetWorkletStore(): void {
|
|
328
|
+
credentialsAccessOrder.clear()
|
|
329
|
+
credentialsAccessCounter = 0
|
|
330
|
+
workletStoreInstance = null
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Get current credentials cache size
|
|
335
|
+
* Useful for monitoring and debugging
|
|
336
|
+
*/
|
|
337
|
+
export function getCredentialsCacheSize(): number {
|
|
338
|
+
const store = getWorkletStore()
|
|
339
|
+
return Object.keys(store.getState().credentialsCache).length
|
|
340
|
+
}
|