@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,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Account Service
|
|
3
|
+
*
|
|
4
|
+
* Handles account method calls through the worklet.
|
|
5
|
+
* This service provides a generic interface for calling account methods
|
|
6
|
+
* like getBalance, getTokenBalance, signMessage, signTransaction, etc.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { convertBigIntToString } from '../utils/balanceUtils'
|
|
10
|
+
import { handleServiceError } from '../utils/errorHandling'
|
|
11
|
+
import { safeStringify } from '../utils/jsonUtils'
|
|
12
|
+
import { workletResponseSchema } from '../utils/schemas'
|
|
13
|
+
import { requireInitialized } from '../utils/storeHelpers'
|
|
14
|
+
import { validateAccountIndex, validateNetworkName } from '../utils/validation'
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Account Service
|
|
18
|
+
*
|
|
19
|
+
* Provides methods for calling account operations through the worklet.
|
|
20
|
+
*/
|
|
21
|
+
export class AccountService {
|
|
22
|
+
/**
|
|
23
|
+
* Call a method on a wallet account
|
|
24
|
+
* Generic method for calling any account method through the worklet
|
|
25
|
+
*
|
|
26
|
+
* The worklet should already have the correct wallet loaded via `initializeWDK`.
|
|
27
|
+
* Wallet switching is handled at the hook level before calling this service.
|
|
28
|
+
*
|
|
29
|
+
* @param network - Network name
|
|
30
|
+
* @param accountIndex - Account index
|
|
31
|
+
* @param methodName - Method name
|
|
32
|
+
* @param args - Optional arguments for the method
|
|
33
|
+
* @param walletId - Optional wallet identifier (for consistency, worklet should already have correct wallet loaded)
|
|
34
|
+
* @returns Promise with the method result
|
|
35
|
+
* @throws Error if validation fails
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```typescript
|
|
39
|
+
* // Get balance
|
|
40
|
+
* const balance = await AccountService.callAccountMethod('ethereum', 0, 'getBalance', null)
|
|
41
|
+
*
|
|
42
|
+
* // Get token balance
|
|
43
|
+
* const tokenBalance = await AccountService.callAccountMethod(
|
|
44
|
+
* 'ethereum',
|
|
45
|
+
* 0,
|
|
46
|
+
* 'getTokenBalance',
|
|
47
|
+
* '0x...'
|
|
48
|
+
* )
|
|
49
|
+
*
|
|
50
|
+
* // Sign a message
|
|
51
|
+
* const signature = await AccountService.callAccountMethod(
|
|
52
|
+
* 'ethereum',
|
|
53
|
+
* 0,
|
|
54
|
+
* 'signMessage',
|
|
55
|
+
* { message: 'Hello World' }
|
|
56
|
+
* )
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
static async callAccountMethod<T = unknown>(
|
|
60
|
+
network: string,
|
|
61
|
+
accountIndex: number,
|
|
62
|
+
methodName: string,
|
|
63
|
+
args?: unknown,
|
|
64
|
+
walletId?: string
|
|
65
|
+
): Promise<T> {
|
|
66
|
+
// Validate methodName parameter
|
|
67
|
+
if (typeof methodName !== 'string' || methodName.trim().length === 0) {
|
|
68
|
+
throw new Error('methodName must be a non-empty string')
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Validate inputs
|
|
72
|
+
validateNetworkName(network)
|
|
73
|
+
validateAccountIndex(accountIndex)
|
|
74
|
+
|
|
75
|
+
// Require initialized worklet
|
|
76
|
+
const hrpc = requireInitialized()
|
|
77
|
+
|
|
78
|
+
// Validate and sanitize args before stringification
|
|
79
|
+
let argsString: string | null = null
|
|
80
|
+
if (args !== undefined && args !== null) {
|
|
81
|
+
// Validate structure and stringify safely
|
|
82
|
+
argsString = safeStringify(args)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
const response = await hrpc.callMethod({
|
|
87
|
+
methodName,
|
|
88
|
+
network,
|
|
89
|
+
accountIndex,
|
|
90
|
+
args: argsString,
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
// Validate response structure
|
|
94
|
+
const validatedResponse = workletResponseSchema.parse(response)
|
|
95
|
+
|
|
96
|
+
if (!validatedResponse.result) {
|
|
97
|
+
throw new Error(`Method ${methodName} returned no result`)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Parse the result and handle BigInt values
|
|
101
|
+
let parsed: T
|
|
102
|
+
try {
|
|
103
|
+
parsed = JSON.parse(validatedResponse.result) as T
|
|
104
|
+
// Basic validation: ensure parsed is not null/undefined
|
|
105
|
+
if (parsed === null || parsed === undefined) {
|
|
106
|
+
throw new Error('Parsed result is null or undefined')
|
|
107
|
+
}
|
|
108
|
+
} catch (error) {
|
|
109
|
+
if (error instanceof Error && error.message.includes('Parsed result is null')) {
|
|
110
|
+
throw error
|
|
111
|
+
}
|
|
112
|
+
throw new Error(`Failed to parse result from ${methodName}: ${error instanceof Error ? error.message : String(error)}`)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Runtime type validation based on method type
|
|
116
|
+
if (methodName === 'getBalance' || methodName === 'getTokenBalance') {
|
|
117
|
+
// Validate balance format
|
|
118
|
+
if (typeof parsed !== 'string' || !/^\d+$/.test(parsed)) {
|
|
119
|
+
throw new Error(`Invalid balance format: ${parsed}`)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Recursively convert BigInt values to strings to prevent serialization errors
|
|
124
|
+
return convertBigIntToString(parsed) as T
|
|
125
|
+
} catch (error) {
|
|
126
|
+
handleServiceError(error, 'AccountService', `callAccountMethod:${methodName}`, {
|
|
127
|
+
network,
|
|
128
|
+
accountIndex,
|
|
129
|
+
methodName,
|
|
130
|
+
})
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Address Service
|
|
3
|
+
*
|
|
4
|
+
* Handles address retrieval and caching operations.
|
|
5
|
+
* This service is focused solely on address management.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { getWalletStore } from '../store/walletStore'
|
|
9
|
+
import { handleServiceError } from '../utils/errorHandling'
|
|
10
|
+
import { requireInitialized, resolveWalletId, updateAddressInState } from '../utils/storeHelpers'
|
|
11
|
+
import { isValidAddress } from '../utils/typeGuards'
|
|
12
|
+
import { validateAccountIndex, validateNetworkName } from '../utils/validation'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Address Service
|
|
16
|
+
*
|
|
17
|
+
* Provides methods for retrieving and caching wallet addresses.
|
|
18
|
+
*/
|
|
19
|
+
export class AddressService {
|
|
20
|
+
/**
|
|
21
|
+
* Get address for a specific network and account index
|
|
22
|
+
* Caches the address in walletStore for future use
|
|
23
|
+
*
|
|
24
|
+
* @param network - Network name
|
|
25
|
+
* @param accountIndex - Account index (default: 0)
|
|
26
|
+
* @param walletId - Optional wallet identifier (defaults to activeWalletId from store)
|
|
27
|
+
*/
|
|
28
|
+
static async getAddress(
|
|
29
|
+
network: string,
|
|
30
|
+
accountIndex = 0,
|
|
31
|
+
walletId?: string
|
|
32
|
+
): Promise<string> {
|
|
33
|
+
// Validate inputs
|
|
34
|
+
validateNetworkName(network)
|
|
35
|
+
validateAccountIndex(accountIndex)
|
|
36
|
+
|
|
37
|
+
const walletStore = getWalletStore()
|
|
38
|
+
const walletState = walletStore.getState()
|
|
39
|
+
|
|
40
|
+
// Resolve walletId from parameter or store
|
|
41
|
+
const targetWalletId = resolveWalletId(walletId)
|
|
42
|
+
|
|
43
|
+
// Check cache first (per-wallet)
|
|
44
|
+
const cachedAddress = walletState.addresses[targetWalletId]?.[network]?.[accountIndex]
|
|
45
|
+
if (cachedAddress) {
|
|
46
|
+
// Validate cached address format
|
|
47
|
+
if (!isValidAddress(cachedAddress)) {
|
|
48
|
+
throw new Error(`Cached address for ${targetWalletId}:${network}:${accountIndex} has invalid format`)
|
|
49
|
+
}
|
|
50
|
+
return cachedAddress
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Require initialized worklet
|
|
54
|
+
const hrpc = requireInitialized()
|
|
55
|
+
|
|
56
|
+
const loadingKey = `${network}-${accountIndex}`
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
// Update loading state (per-wallet)
|
|
60
|
+
walletStore.setState((prev) => ({
|
|
61
|
+
walletLoading: {
|
|
62
|
+
...prev.walletLoading,
|
|
63
|
+
[targetWalletId]: {
|
|
64
|
+
...(prev.walletLoading[targetWalletId] || {}),
|
|
65
|
+
[loadingKey]: true,
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
}))
|
|
69
|
+
|
|
70
|
+
// Call getAddress method on the account
|
|
71
|
+
const response = await hrpc.callMethod({
|
|
72
|
+
methodName: 'getAddress',
|
|
73
|
+
network,
|
|
74
|
+
accountIndex,
|
|
75
|
+
args: null,
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
if (!response.result) {
|
|
79
|
+
throw new Error('Failed to get address from worklet')
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
let address: string
|
|
83
|
+
try {
|
|
84
|
+
const parsed = JSON.parse(response.result)
|
|
85
|
+
if (typeof parsed !== 'string') {
|
|
86
|
+
throw new Error('Address must be a string')
|
|
87
|
+
}
|
|
88
|
+
// Runtime validation of address format
|
|
89
|
+
if (!isValidAddress(parsed)) {
|
|
90
|
+
throw new Error(`Address from worklet has invalid format: ${parsed}`)
|
|
91
|
+
}
|
|
92
|
+
address = parsed
|
|
93
|
+
} catch (error) {
|
|
94
|
+
throw new Error(`Failed to parse address from worklet response: ${error instanceof Error ? error.message : String(error)}`)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Cache the address using helper (per-wallet)
|
|
98
|
+
walletStore.setState((prev) => ({
|
|
99
|
+
...updateAddressInState(prev, targetWalletId, network, accountIndex, address),
|
|
100
|
+
walletLoading: {
|
|
101
|
+
...prev.walletLoading,
|
|
102
|
+
[targetWalletId]: {
|
|
103
|
+
...(prev.walletLoading[targetWalletId] || {}),
|
|
104
|
+
[loadingKey]: false,
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
}))
|
|
108
|
+
|
|
109
|
+
return address
|
|
110
|
+
} catch (error) {
|
|
111
|
+
// Update loading state on error (per-wallet)
|
|
112
|
+
walletStore.setState((prev) => ({
|
|
113
|
+
walletLoading: {
|
|
114
|
+
...prev.walletLoading,
|
|
115
|
+
[targetWalletId]: {
|
|
116
|
+
...(prev.walletLoading[targetWalletId] || {}),
|
|
117
|
+
[loadingKey]: false,
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
}))
|
|
121
|
+
handleServiceError(error, 'AddressService', 'getAddress', { network, accountIndex, walletId: targetWalletId })
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Balance Service
|
|
3
|
+
*
|
|
4
|
+
* Handles balance operations: getting, setting, updating, and managing balance state.
|
|
5
|
+
* This service is focused solely on balance management.
|
|
6
|
+
*
|
|
7
|
+
* ## Storage Strategy - Single Source of Truth
|
|
8
|
+
*
|
|
9
|
+
* This service manages balances in the Zustand store (walletStore.balances), which is
|
|
10
|
+
* the **single source of truth** for all balance data.
|
|
11
|
+
*
|
|
12
|
+
* **Architecture**:
|
|
13
|
+
* - **Zustand Store (Single Source of Truth)**: Stores and persists balances across app restarts (via MMKV)
|
|
14
|
+
* - **TanStack Query (Fetching Layer)**: Handles fetching, caching, and refetching (reads from and updates Zustand)
|
|
15
|
+
*
|
|
16
|
+
* **Data Flow**:
|
|
17
|
+
* 1. TanStack Query reads initial data from Zustand (via `initialData` in useBalance hooks)
|
|
18
|
+
* 2. TanStack Query fetches fresh balance from worklet when needed
|
|
19
|
+
* 3. After successful fetch, TanStack Query updates Zustand via this service (single source of truth update)
|
|
20
|
+
* 4. Components read from TanStack Query, which ensures consistency with Zustand
|
|
21
|
+
*
|
|
22
|
+
* **Sync Guarantees**:
|
|
23
|
+
* - Zustand is always the source of truth - all reads and writes go through Zustand
|
|
24
|
+
* - TanStack Query updates Zustand directly after fetch (no separate sync step)
|
|
25
|
+
* - Initial data consistency - TanStack Query uses Zustand's persisted data on app start
|
|
26
|
+
* - No race conditions - all updates are atomic through Zustand
|
|
27
|
+
*
|
|
28
|
+
* **Usage**:
|
|
29
|
+
* - Direct access: Use `BalanceService.getBalance()` to read from Zustand directly (rare, prefer TanStack Query hooks)
|
|
30
|
+
* - Updates: TanStack Query calls `BalanceService.updateBalance()` after fetch (automatic)
|
|
31
|
+
* - Preferred: Use `useBalance()` hooks which handle Zustand integration automatically
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
import { getWalletStore } from '../store/walletStore'
|
|
35
|
+
import { resolveWalletId, updateBalanceInState, getNestedState } from '../utils/storeHelpers'
|
|
36
|
+
import { NATIVE_TOKEN_KEY } from '../utils/constants'
|
|
37
|
+
import { validateBalance, validateWalletParams } from '../utils/validation'
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Balance Service
|
|
41
|
+
*
|
|
42
|
+
* Provides methods for managing wallet balances.
|
|
43
|
+
*/
|
|
44
|
+
export class BalanceService {
|
|
45
|
+
/**
|
|
46
|
+
* Validate wallet parameters and balance (if provided)
|
|
47
|
+
* Helper to reduce repetitive validation calls
|
|
48
|
+
*/
|
|
49
|
+
private static validateBalanceParams(
|
|
50
|
+
network: string,
|
|
51
|
+
accountIndex: number,
|
|
52
|
+
tokenAddress?: string | null,
|
|
53
|
+
balance?: string
|
|
54
|
+
): void {
|
|
55
|
+
validateWalletParams(network, accountIndex, tokenAddress)
|
|
56
|
+
if (balance !== undefined) {
|
|
57
|
+
validateBalance(balance)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Get token key from token address (native or token address)
|
|
63
|
+
*/
|
|
64
|
+
private static getTokenKey(tokenAddress: string | null): string {
|
|
65
|
+
return tokenAddress || NATIVE_TOKEN_KEY
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Update balance for a specific wallet, network, and token
|
|
69
|
+
*
|
|
70
|
+
* @param accountIndex - Account index
|
|
71
|
+
* @param network - Network name
|
|
72
|
+
* @param tokenAddress - Token address (null for native)
|
|
73
|
+
* @param balance - Balance value
|
|
74
|
+
* @param walletId - Optional wallet identifier (defaults to activeWalletId from store)
|
|
75
|
+
*/
|
|
76
|
+
static updateBalance(
|
|
77
|
+
accountIndex: number,
|
|
78
|
+
network: string,
|
|
79
|
+
tokenAddress: string | null,
|
|
80
|
+
balance: string,
|
|
81
|
+
walletId?: string
|
|
82
|
+
): void {
|
|
83
|
+
this.validateBalanceParams(network, accountIndex, tokenAddress, balance)
|
|
84
|
+
|
|
85
|
+
const walletStore = getWalletStore()
|
|
86
|
+
const walletState = walletStore.getState()
|
|
87
|
+
const targetWalletId = resolveWalletId(walletId)
|
|
88
|
+
const tokenKey = this.getTokenKey(tokenAddress)
|
|
89
|
+
|
|
90
|
+
walletStore.setState((prev) => ({
|
|
91
|
+
...updateBalanceInState(prev, targetWalletId, network, accountIndex, tokenKey, balance),
|
|
92
|
+
}))
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Get balance for a specific wallet, network, and token
|
|
97
|
+
*
|
|
98
|
+
* @param accountIndex - Account index
|
|
99
|
+
* @param network - Network name
|
|
100
|
+
* @param tokenAddress - Token address (null for native)
|
|
101
|
+
* @param walletId - Optional wallet identifier (defaults to activeWalletId from store)
|
|
102
|
+
*/
|
|
103
|
+
static getBalance(
|
|
104
|
+
accountIndex: number,
|
|
105
|
+
network: string,
|
|
106
|
+
tokenAddress: string | null,
|
|
107
|
+
walletId?: string
|
|
108
|
+
): string | null {
|
|
109
|
+
this.validateBalanceParams(network, accountIndex, tokenAddress)
|
|
110
|
+
|
|
111
|
+
const walletStore = getWalletStore()
|
|
112
|
+
const walletState = walletStore.getState()
|
|
113
|
+
const targetWalletId = resolveWalletId(walletId)
|
|
114
|
+
const tokenKey = this.getTokenKey(tokenAddress)
|
|
115
|
+
|
|
116
|
+
return getNestedState(
|
|
117
|
+
walletState.balances,
|
|
118
|
+
[targetWalletId, network, accountIndex, tokenKey],
|
|
119
|
+
null
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Get all balances for a specific wallet and network
|
|
125
|
+
*
|
|
126
|
+
* @param accountIndex - Account index
|
|
127
|
+
* @param network - Network name
|
|
128
|
+
* @param walletId - Optional wallet identifier (defaults to activeWalletId from store)
|
|
129
|
+
*/
|
|
130
|
+
static getBalancesForWallet(
|
|
131
|
+
accountIndex: number,
|
|
132
|
+
network: string,
|
|
133
|
+
walletId?: string
|
|
134
|
+
): Record<string, string> | null {
|
|
135
|
+
// Validate inputs
|
|
136
|
+
validateWalletParams(network, accountIndex)
|
|
137
|
+
|
|
138
|
+
const walletStore = getWalletStore()
|
|
139
|
+
const walletState = walletStore.getState()
|
|
140
|
+
const targetWalletId = resolveWalletId(walletId)
|
|
141
|
+
|
|
142
|
+
return getNestedState(
|
|
143
|
+
walletState.balances,
|
|
144
|
+
[targetWalletId, network, accountIndex],
|
|
145
|
+
null
|
|
146
|
+
)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Set balance loading state
|
|
151
|
+
*
|
|
152
|
+
* @param network - Network name
|
|
153
|
+
* @param accountIndex - Account index
|
|
154
|
+
* @param tokenAddress - Token address (null for native)
|
|
155
|
+
* @param loading - Loading state
|
|
156
|
+
* @param walletId - Optional wallet identifier (defaults to activeWalletId from store)
|
|
157
|
+
*/
|
|
158
|
+
static setBalanceLoading(
|
|
159
|
+
network: string,
|
|
160
|
+
accountIndex: number,
|
|
161
|
+
tokenAddress: string | null,
|
|
162
|
+
loading: boolean,
|
|
163
|
+
walletId?: string
|
|
164
|
+
): void {
|
|
165
|
+
this.validateBalanceParams(network, accountIndex, tokenAddress)
|
|
166
|
+
|
|
167
|
+
const walletStore = getWalletStore()
|
|
168
|
+
const walletState = walletStore.getState()
|
|
169
|
+
const targetWalletId = resolveWalletId(walletId)
|
|
170
|
+
const tokenKey = this.getTokenKey(tokenAddress)
|
|
171
|
+
const loadingKey = `${network}-${accountIndex}-${tokenKey}`
|
|
172
|
+
|
|
173
|
+
walletStore.setState((prev) => ({
|
|
174
|
+
balanceLoading: {
|
|
175
|
+
...prev.balanceLoading,
|
|
176
|
+
[targetWalletId]: loading
|
|
177
|
+
? { ...(prev.balanceLoading[targetWalletId] || {}), [loadingKey]: true }
|
|
178
|
+
: Object.fromEntries(
|
|
179
|
+
Object.entries(prev.balanceLoading[targetWalletId] || {}).filter(([key]) => key !== loadingKey)
|
|
180
|
+
),
|
|
181
|
+
},
|
|
182
|
+
}))
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Check if balance is loading
|
|
187
|
+
*
|
|
188
|
+
* @param network - Network name
|
|
189
|
+
* @param accountIndex - Account index
|
|
190
|
+
* @param tokenAddress - Token address (null for native)
|
|
191
|
+
* @param walletId - Optional wallet identifier (defaults to activeWalletId from store)
|
|
192
|
+
*/
|
|
193
|
+
static isBalanceLoading(
|
|
194
|
+
network: string,
|
|
195
|
+
accountIndex: number,
|
|
196
|
+
tokenAddress: string | null,
|
|
197
|
+
walletId?: string
|
|
198
|
+
): boolean {
|
|
199
|
+
this.validateBalanceParams(network, accountIndex, tokenAddress)
|
|
200
|
+
|
|
201
|
+
const walletStore = getWalletStore()
|
|
202
|
+
const walletState = walletStore.getState()
|
|
203
|
+
const targetWalletId = walletId || walletState.activeWalletId
|
|
204
|
+
if (!targetWalletId) {
|
|
205
|
+
return false
|
|
206
|
+
}
|
|
207
|
+
const tokenKey = this.getTokenKey(tokenAddress)
|
|
208
|
+
const loadingKey = `${network}-${accountIndex}-${tokenKey}`
|
|
209
|
+
|
|
210
|
+
return getNestedState(
|
|
211
|
+
walletState.balanceLoading,
|
|
212
|
+
[targetWalletId, loadingKey],
|
|
213
|
+
false
|
|
214
|
+
)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Update last balance update timestamp
|
|
219
|
+
*
|
|
220
|
+
* @param network - Network name
|
|
221
|
+
* @param accountIndex - Account index
|
|
222
|
+
* @param walletId - Optional wallet identifier (defaults to activeWalletId from store)
|
|
223
|
+
*/
|
|
224
|
+
static updateLastBalanceUpdate(
|
|
225
|
+
network: string,
|
|
226
|
+
accountIndex: number,
|
|
227
|
+
walletId?: string
|
|
228
|
+
): void {
|
|
229
|
+
// Validate inputs
|
|
230
|
+
validateWalletParams(network, accountIndex)
|
|
231
|
+
|
|
232
|
+
const walletStore = getWalletStore()
|
|
233
|
+
const walletState = walletStore.getState()
|
|
234
|
+
const targetWalletId = resolveWalletId(walletId)
|
|
235
|
+
const now = Date.now()
|
|
236
|
+
|
|
237
|
+
walletStore.setState((prev) => ({
|
|
238
|
+
lastBalanceUpdate: {
|
|
239
|
+
...prev.lastBalanceUpdate,
|
|
240
|
+
[targetWalletId]: {
|
|
241
|
+
...(prev.lastBalanceUpdate[targetWalletId] || {}),
|
|
242
|
+
[network]: {
|
|
243
|
+
...(prev.lastBalanceUpdate[targetWalletId]?.[network] || {}),
|
|
244
|
+
[accountIndex]: now,
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
}))
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Get last balance update timestamp
|
|
253
|
+
*
|
|
254
|
+
* @param network - Network name
|
|
255
|
+
* @param accountIndex - Account index
|
|
256
|
+
* @param walletId - Optional wallet identifier (defaults to activeWalletId from store)
|
|
257
|
+
*/
|
|
258
|
+
static getLastBalanceUpdate(
|
|
259
|
+
network: string,
|
|
260
|
+
accountIndex: number,
|
|
261
|
+
walletId?: string
|
|
262
|
+
): number | null {
|
|
263
|
+
// Validate inputs
|
|
264
|
+
validateWalletParams(network, accountIndex)
|
|
265
|
+
|
|
266
|
+
const walletStore = getWalletStore()
|
|
267
|
+
const walletState = walletStore.getState()
|
|
268
|
+
const targetWalletId = resolveWalletId(walletId)
|
|
269
|
+
|
|
270
|
+
return getNestedState(
|
|
271
|
+
walletState.lastBalanceUpdate,
|
|
272
|
+
[targetWalletId, network, accountIndex],
|
|
273
|
+
null
|
|
274
|
+
)
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Clear all balances (useful for wallet reset)
|
|
279
|
+
*/
|
|
280
|
+
static clearBalances(): void {
|
|
281
|
+
const walletStore = getWalletStore()
|
|
282
|
+
|
|
283
|
+
walletStore.setState({
|
|
284
|
+
balances: {},
|
|
285
|
+
balanceLoading: {},
|
|
286
|
+
lastBalanceUpdate: {},
|
|
287
|
+
})
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
|