@explorins/pers-sdk-react-native 1.5.18 → 1.5.20
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 +336 -234
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/useAuth.d.ts +1 -1
- package/dist/hooks/useAuth.d.ts.map +1 -1
- package/dist/hooks/useAuth.js +7 -7
- package/dist/hooks/useRedemptions.d.ts.map +1 -1
- package/dist/hooks/useRedemptions.js +4 -4
- package/dist/hooks/useTenants.d.ts.map +1 -1
- package/dist/hooks/useTenants.js +0 -1
- package/dist/hooks/useTransactionSigner.d.ts +186 -53
- package/dist/hooks/useTransactionSigner.d.ts.map +1 -1
- package/dist/hooks/useTransactionSigner.js +285 -102
- package/dist/hooks/useTransactions.d.ts +2 -2
- package/dist/hooks/useTransactions.d.ts.map +1 -1
- package/dist/hooks/useTransactions.js +9 -10
- package/dist/index.d.ts +211 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20918 -18336
- package/dist/index.js.map +1 -1
- package/dist/providers/PersSDKProvider.d.ts +2 -8
- package/dist/providers/PersSDKProvider.d.ts.map +1 -1
- package/dist/providers/PersSDKProvider.js +16 -31
- package/dist/providers/react-native-auth-provider.d.ts +25 -36
- package/dist/providers/react-native-auth-provider.d.ts.map +1 -1
- package/dist/providers/react-native-auth-provider.js +36 -146
- package/dist/storage/async-storage-token-storage.d.ts +22 -0
- package/dist/storage/async-storage-token-storage.d.ts.map +1 -0
- package/dist/storage/async-storage-token-storage.js +113 -0
- package/package.json +16 -11
- package/src/hooks/index.ts +1 -1
- package/src/hooks/useAuth.ts +7 -7
- package/src/hooks/useRedemptions.ts +5 -7
- package/src/hooks/useTenants.ts +0 -1
- package/src/hooks/useTransactionSigner.ts +322 -166
- package/src/hooks/useTransactions.ts +12 -11
- package/src/index.ts +243 -7
- package/src/providers/PersSDKProvider.tsx +21 -40
- package/src/providers/react-native-auth-provider.ts +59 -176
- package/src/storage/async-storage-token-storage.ts +133 -0
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { useCallback, useState, useRef, useEffect } from 'react';
|
|
2
|
-
import { usePersSDK } from '../providers/PersSDKProvider';
|
|
3
2
|
// Dynamic import the signer SDK to avoid build issues with static dependencies
|
|
4
3
|
let createPersSignerSDK = null;
|
|
5
4
|
try {
|
|
6
5
|
const signerModule = require('@explorins/pers-signer/react-native');
|
|
7
6
|
createPersSignerSDK = signerModule.createPersSignerSDK;
|
|
8
|
-
console.log('[useTransactionSigner] PERS Signer SDK loaded successfully');
|
|
9
7
|
}
|
|
10
8
|
catch (error) {
|
|
11
9
|
console.warn('[useTransactionSigner] PERS Signer SDK not available:', error.message);
|
|
@@ -16,53 +14,199 @@ const DEFAULT_ETHERS_PROVIDER = "https://sepolia.infura.io/v3/2781b4b5242343d5b0
|
|
|
16
14
|
/**
|
|
17
15
|
* React Native hook for blockchain transaction signing using PERS Signer SDK
|
|
18
16
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
17
|
+
* This hook provides a complete blockchain transaction signing solution for React Native
|
|
18
|
+
* applications, integrating with the PERS ecosystem for tourism loyalty and reward systems.
|
|
19
|
+
* It automatically handles WebAuthn authentication, transaction preparation, signing, and
|
|
20
|
+
* blockchain submission in a single convenient interface.
|
|
21
|
+
*
|
|
22
|
+
* **Features:**
|
|
23
|
+
* - Automatic WebAuthn provider initialization for React Native
|
|
24
|
+
* - 5-minute authentication caching to reduce repeated logins
|
|
25
|
+
* - Complete transaction lifecycle management (sign + submit)
|
|
26
|
+
* - Comprehensive error handling with detailed error messages
|
|
27
|
+
* - Real-time status monitoring for UI feedback
|
|
28
|
+
* - Automatic retry logic for network failures
|
|
29
|
+
*
|
|
30
|
+
* **Underlying SDK Methods:**
|
|
31
|
+
* The hook uses the PERS Signer SDK which provides 5 core methods:
|
|
32
|
+
* 1. `loginUser(jwtToken)` - Authenticate user with 5-minute caching
|
|
33
|
+
* 2. `signTransaction(signingData, jwtToken)` - Sign transactions with auto-login
|
|
34
|
+
* 3. `submitTransaction(signingResult, jwtToken)` - Submit signed transactions
|
|
35
|
+
* 4. `signPersTransaction(jwtToken)` - Legacy one-liner for backward compatibility
|
|
36
|
+
* 5. `signAndSubmitPersTransaction(jwtToken)` - Complete sign + submit flow (used by this hook)
|
|
37
|
+
*
|
|
38
|
+
* **Security:**
|
|
39
|
+
* - WebAuthn-based secure authentication (no passwords stored)
|
|
40
|
+
* - JWT token validation and expiration checking
|
|
41
|
+
* - Secure transaction signing using device biometrics/PIN
|
|
42
|
+
* - No sensitive data stored locally
|
|
43
|
+
*
|
|
44
|
+
* @returns {TransactionSignerHook} Hook interface with signing methods and status
|
|
21
45
|
*
|
|
22
46
|
* @example
|
|
47
|
+
* **Basic Usage:**
|
|
23
48
|
* ```typescript
|
|
24
|
-
*
|
|
25
|
-
*
|
|
49
|
+
* import { useTransactionSigner } from '@explorins/pers-sdk-react-native';
|
|
50
|
+
*
|
|
51
|
+
* function TransactionScreen() {
|
|
52
|
+
* const {
|
|
53
|
+
* signAndSubmitTransactionWithJWT,
|
|
54
|
+
* isSignerAvailable,
|
|
55
|
+
* isSignerInitialized
|
|
56
|
+
* } = useTransactionSigner();
|
|
26
57
|
*
|
|
27
58
|
* const handleSign = async (jwtFromRedemption: string) => {
|
|
59
|
+
* if (!isSignerAvailable) {
|
|
60
|
+
* console.error('Signer not available');
|
|
61
|
+
* return;
|
|
62
|
+
* }
|
|
63
|
+
*
|
|
28
64
|
* try {
|
|
29
|
-
* const result = await
|
|
65
|
+
* const result = await signAndSubmitTransactionWithJWT(jwtFromRedemption);
|
|
30
66
|
* if (result.success) {
|
|
31
|
-
* console.log('Transaction
|
|
67
|
+
* console.log('Transaction completed:', result.transactionHash);
|
|
68
|
+
* // Handle successful transaction
|
|
69
|
+
* if (result.shouldRedirect && result.redirectUrl) {
|
|
70
|
+
* // Navigate to success page or external URL
|
|
71
|
+
* }
|
|
32
72
|
* }
|
|
33
73
|
* } catch (error) {
|
|
34
|
-
* console.error('
|
|
74
|
+
* console.error('Transaction failed:', error.message);
|
|
75
|
+
* // Handle error (show user-friendly message)
|
|
35
76
|
* }
|
|
36
77
|
* };
|
|
37
78
|
*
|
|
38
79
|
* return (
|
|
39
|
-
* <
|
|
40
|
-
*
|
|
41
|
-
*
|
|
80
|
+
* <View style={styles.container}>
|
|
81
|
+
* <TouchableOpacity
|
|
82
|
+
* onPress={() => handleSign(redeemJWT)}
|
|
83
|
+
* disabled={!isSignerAvailable}
|
|
84
|
+
* style={[styles.button, !isSignerAvailable && styles.disabled]}
|
|
85
|
+
* >
|
|
86
|
+
* <Text style={styles.buttonText}>
|
|
87
|
+
* {isSignerInitialized ? 'Sign Transaction' : 'Initializing...'}
|
|
88
|
+
* </Text>
|
|
89
|
+
* </TouchableOpacity>
|
|
90
|
+
* </View>
|
|
42
91
|
* );
|
|
43
92
|
* }
|
|
44
93
|
* ```
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* **Advanced Usage with Error Handling:**
|
|
97
|
+
* ```typescript
|
|
98
|
+
* function AdvancedTransactionComponent() {
|
|
99
|
+
* const [isLoading, setIsLoading] = useState(false);
|
|
100
|
+
* const [error, setError] = useState<string | null>(null);
|
|
101
|
+
* const { signAndSubmitTransactionWithJWT, isSignerAvailable } = useTransactionSigner();
|
|
102
|
+
*
|
|
103
|
+
* const handleTransaction = async (jwt: string) => {
|
|
104
|
+
* setIsLoading(true);
|
|
105
|
+
* setError(null);
|
|
106
|
+
*
|
|
107
|
+
* try {
|
|
108
|
+
* const result = await signAndSubmitTransactionWithJWT(jwt);
|
|
109
|
+
*
|
|
110
|
+
* if (result.success) {
|
|
111
|
+
* // Success handling
|
|
112
|
+
* Alert.alert(
|
|
113
|
+
* 'Success',
|
|
114
|
+
* `Transaction completed!\nHash: ${result.transactionHash}`
|
|
115
|
+
* );
|
|
116
|
+
* } else {
|
|
117
|
+
* throw new Error(result.error || 'Transaction failed');
|
|
118
|
+
* }
|
|
119
|
+
* } catch (err) {
|
|
120
|
+
* const errorMessage = err instanceof Error ? err.message : 'Unknown error';
|
|
121
|
+
* setError(errorMessage);
|
|
122
|
+
*
|
|
123
|
+
* // Different error handling based on error type
|
|
124
|
+
* if (errorMessage.includes('expired')) {
|
|
125
|
+
* Alert.alert('Session Expired', 'Please log in again');
|
|
126
|
+
* } else if (errorMessage.includes('network')) {
|
|
127
|
+
* Alert.alert('Network Error', 'Please check your connection');
|
|
128
|
+
* } else {
|
|
129
|
+
* Alert.alert('Transaction Failed', errorMessage);
|
|
130
|
+
* }
|
|
131
|
+
* } finally {
|
|
132
|
+
* setIsLoading(false);
|
|
133
|
+
* }
|
|
134
|
+
* };
|
|
135
|
+
*
|
|
136
|
+
* return (
|
|
137
|
+
* <View>
|
|
138
|
+
* {error && (
|
|
139
|
+
* <Text style={styles.errorText}>{error}</Text>
|
|
140
|
+
* )}
|
|
141
|
+
* <TouchableOpacity
|
|
142
|
+
* onPress={() => handleTransaction(jwtToken)}
|
|
143
|
+
* disabled={!isSignerAvailable || isLoading}
|
|
144
|
+
* >
|
|
145
|
+
* <Text>
|
|
146
|
+
* {isLoading ? 'Processing...' : 'Sign & Submit Transaction'}
|
|
147
|
+
* </Text>
|
|
148
|
+
* </TouchableOpacity>
|
|
149
|
+
* </View>
|
|
150
|
+
* );
|
|
151
|
+
* }
|
|
152
|
+
* ```
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* **Integration with PERS SDK:**
|
|
156
|
+
* ```typescript
|
|
157
|
+
* import { usePersSDK } from '@explorins/pers-sdk-react-native';
|
|
158
|
+
* import { useTransactionSigner } from '@explorins/pers-sdk-react-native';
|
|
159
|
+
*
|
|
160
|
+
* function RedemptionFlow() {
|
|
161
|
+
* const { user, redeemTokens } = usePersSDK();
|
|
162
|
+
* const { signAndSubmitTransactionWithJWT } = useTransactionSigner();
|
|
163
|
+
*
|
|
164
|
+
* const handleRedemption = async (tokenAmount: number) => {
|
|
165
|
+
* try {
|
|
166
|
+
* // Step 1: Create redemption with PERS SDK
|
|
167
|
+
* const redemption = await redeemTokens({
|
|
168
|
+
* tokenAmount,
|
|
169
|
+
* destinationAddress: user?.walletAddress
|
|
170
|
+
* });
|
|
171
|
+
*
|
|
172
|
+
* // Step 2: Sign and submit transaction
|
|
173
|
+
* const txResult = await signAndSubmitTransactionWithJWT(redemption.jwtToken);
|
|
174
|
+
*
|
|
175
|
+
* if (txResult.success) {
|
|
176
|
+
* console.log('Redemption completed:', txResult.transactionHash);
|
|
177
|
+
* }
|
|
178
|
+
* } catch (error) {
|
|
179
|
+
* console.error('Redemption failed:', error);
|
|
180
|
+
* }
|
|
181
|
+
* };
|
|
182
|
+
* }
|
|
183
|
+
* ```
|
|
184
|
+
*
|
|
185
|
+
* @see {@link SubmissionResult} for transaction result structure
|
|
186
|
+
* @see {@link TransactionSigningResult} for signing result details
|
|
187
|
+
* @see {@link AuthenticatedUser} for user authentication data
|
|
188
|
+
*
|
|
189
|
+
* @since 1.5.0
|
|
45
190
|
*/
|
|
46
191
|
export const useTransactionSigner = () => {
|
|
47
|
-
const { isInitialized, isAuthenticated, user } = usePersSDK();
|
|
192
|
+
// const { isInitialized, isAuthenticated, user } = usePersSDK();
|
|
48
193
|
const [isSignerInitialized, setIsSignerInitialized] = useState(false);
|
|
49
194
|
const signerSDKRef = useRef(null);
|
|
50
195
|
// Auto-initialize signer SDK when PERS SDK is ready
|
|
51
196
|
useEffect(() => {
|
|
52
|
-
console.log('[useTransactionSigner] Auto-initializing signer SDK...');
|
|
53
197
|
const initializeSignerSDK = async () => {
|
|
54
198
|
if (!createPersSignerSDK) {
|
|
55
199
|
console.warn('[useTransactionSigner] Signer SDK not available');
|
|
56
200
|
return;
|
|
57
201
|
}
|
|
58
202
|
try {
|
|
59
|
-
|
|
203
|
+
// React Native createPersSignerSDK automatically includes WebAuthn provider
|
|
60
204
|
const signerSDK = await createPersSignerSDK({
|
|
61
|
-
ethersProviderUrl: DEFAULT_ETHERS_PROVIDER
|
|
205
|
+
ethersProviderUrl: DEFAULT_ETHERS_PROVIDER,
|
|
206
|
+
relyingPartyName: 'PERS React Native App'
|
|
62
207
|
});
|
|
63
208
|
signerSDKRef.current = signerSDK;
|
|
64
209
|
setIsSignerInitialized(true);
|
|
65
|
-
console.log('[useTransactionSigner] PERS Signer SDK initialized successfully');
|
|
66
210
|
}
|
|
67
211
|
catch (error) {
|
|
68
212
|
console.error('[useTransactionSigner] Failed to initialize signer SDK:', error);
|
|
@@ -73,17 +217,85 @@ export const useTransactionSigner = () => {
|
|
|
73
217
|
}
|
|
74
218
|
}, [isSignerInitialized]);
|
|
75
219
|
/**
|
|
76
|
-
* Sign a blockchain transaction using JWT token
|
|
220
|
+
* Sign and submit a blockchain transaction using JWT token
|
|
221
|
+
*
|
|
222
|
+
* This is the main method for executing blockchain transactions in React Native.
|
|
223
|
+
* It handles the complete transaction lifecycle: authentication, signing, and
|
|
224
|
+
* blockchain submission in a single call.
|
|
225
|
+
*
|
|
226
|
+
* **Process Flow:**
|
|
227
|
+
* 1. Validates the JWT token and extracts transaction data
|
|
228
|
+
* 2. Authenticates the user using WebAuthn (cached for 5 minutes)
|
|
229
|
+
* 3. Fetches transaction data from PERS backend
|
|
230
|
+
* 4. Signs the transaction using device security (biometrics/PIN)
|
|
231
|
+
* 5. Submits the signed transaction to the blockchain
|
|
232
|
+
* 6. Returns detailed result with transaction hash and status
|
|
233
|
+
*
|
|
234
|
+
* **Security Features:**
|
|
235
|
+
* - JWT token validation and expiration checking
|
|
236
|
+
* - WebAuthn authentication with device biometrics
|
|
237
|
+
* - Secure transaction signing without exposing private keys
|
|
238
|
+
* - Automatic session management with secure caching
|
|
77
239
|
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
* 3. Sign transaction with authenticated user
|
|
240
|
+
* @param {string} jwt - JWT token containing transaction ID and user information
|
|
241
|
+
* Must include: `transactionId`, `identifierEmail`, `tenantId`
|
|
242
|
+
* @returns {Promise<SubmissionResult>} Complete transaction result
|
|
82
243
|
*
|
|
83
|
-
* @
|
|
84
|
-
* @
|
|
244
|
+
* @throws {Error} 'Transaction signer not initialized' - Hook not ready
|
|
245
|
+
* @throws {Error} 'PERS Signer SDK not available' - SDK installation issue
|
|
246
|
+
* @throws {Error} 'Invalid or expired JWT token' - Token validation failed
|
|
247
|
+
* @throws {Error} 'Authentication failed' - WebAuthn authentication failed
|
|
248
|
+
* @throws {Error} 'Transaction signing failed' - Signing process failed
|
|
249
|
+
* @throws {Error} 'Transaction submission failed' - Blockchain submission failed
|
|
250
|
+
*
|
|
251
|
+
* @example
|
|
252
|
+
* **Basic Transaction:**
|
|
253
|
+
* ```typescript
|
|
254
|
+
* const { signAndSubmitTransactionWithJWT } = useTransactionSigner();
|
|
255
|
+
*
|
|
256
|
+
* const result = await signAndSubmitTransactionWithJWT(jwtToken);
|
|
257
|
+
* if (result.success) {
|
|
258
|
+
* console.log('Transaction Hash:', result.transactionHash);
|
|
259
|
+
* console.log('Blockchain explorer: [Chain-specific explorer URL]');
|
|
260
|
+
* }
|
|
261
|
+
* ```
|
|
262
|
+
*
|
|
263
|
+
* @example
|
|
264
|
+
* **With Error Handling:**
|
|
265
|
+
* ```typescript
|
|
266
|
+
* try {
|
|
267
|
+
* const result = await signAndSubmitTransactionWithJWT(redeemJWT);
|
|
268
|
+
*
|
|
269
|
+
* if (result.success) {
|
|
270
|
+
* // Transaction successful
|
|
271
|
+
* setTransactionHash(result.transactionHash);
|
|
272
|
+
*
|
|
273
|
+
* if (result.shouldRedirect && result.redirectUrl) {
|
|
274
|
+
* // Handle post-transaction redirect
|
|
275
|
+
* Linking.openURL(result.redirectUrl);
|
|
276
|
+
* }
|
|
277
|
+
* } else {
|
|
278
|
+
* // Transaction failed but didn't throw
|
|
279
|
+
* setError(result.error || 'Transaction failed');
|
|
280
|
+
* }
|
|
281
|
+
* } catch (error) {
|
|
282
|
+
* // Handle different error types
|
|
283
|
+
* if (error.message.includes('expired')) {
|
|
284
|
+
* // Token expired - redirect to login
|
|
285
|
+
* navigation.navigate('Login');
|
|
286
|
+
* } else if (error.message.includes('network')) {
|
|
287
|
+
* // Network error - suggest retry
|
|
288
|
+
* setError('Network error. Please try again.');
|
|
289
|
+
* } else {
|
|
290
|
+
* // Other errors
|
|
291
|
+
* setError(error.message);
|
|
292
|
+
* }
|
|
293
|
+
* }
|
|
294
|
+
* ```
|
|
295
|
+
*
|
|
296
|
+
* @see {@link SubmissionResult} for detailed result structure
|
|
85
297
|
*/
|
|
86
|
-
const
|
|
298
|
+
const signAndSubmitTransactionWithJWT = useCallback(async (jwt) => {
|
|
87
299
|
if (!isSignerInitialized || !signerSDKRef.current) {
|
|
88
300
|
throw new Error('Transaction signer not initialized');
|
|
89
301
|
}
|
|
@@ -91,95 +303,66 @@ export const useTransactionSigner = () => {
|
|
|
91
303
|
throw new Error('PERS Signer SDK not available. Blockchain signing is not supported.');
|
|
92
304
|
}
|
|
93
305
|
try {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
searchParams.set('jwt', jwt);
|
|
98
|
-
// Step 1: Authenticate with JWT (handles tenant setup, project keys automatically)
|
|
99
|
-
console.log('[useTransactionSigner] Authenticating with JWT...');
|
|
100
|
-
const authResult = await signerSDKRef.current.authenticateWithJWT(searchParams);
|
|
101
|
-
if (!authResult) {
|
|
102
|
-
throw new Error('JWT authentication failed - no valid token found');
|
|
103
|
-
}
|
|
104
|
-
if (authResult.isExpired) {
|
|
105
|
-
throw new Error('JWT token is expired');
|
|
106
|
-
}
|
|
107
|
-
console.log('[useTransactionSigner] JWT authentication successful:', authResult.user.identifier);
|
|
108
|
-
// Step 2: Extract transaction ID from JWT
|
|
109
|
-
const jwtParts = jwt.split('.');
|
|
110
|
-
if (jwtParts.length !== 3) {
|
|
111
|
-
throw new Error('Invalid JWT token format');
|
|
112
|
-
}
|
|
113
|
-
const payload = JSON.parse(atob(jwtParts[1]));
|
|
114
|
-
const transactionId = payload.transactionId;
|
|
115
|
-
if (!transactionId) {
|
|
116
|
-
throw new Error('No transaction ID found in JWT token');
|
|
117
|
-
}
|
|
118
|
-
console.log('[useTransactionSigner] Found transaction ID:', transactionId);
|
|
119
|
-
// Step 3: Sign transaction using authenticated user
|
|
120
|
-
console.log('[useTransactionSigner] Signing transaction...');
|
|
121
|
-
const signingResult = await signerSDKRef.current.signPersTransaction(authResult.user, transactionId);
|
|
122
|
-
console.log('[useTransactionSigner] Transaction signing result:', signingResult);
|
|
123
|
-
return {
|
|
124
|
-
success: signingResult.success,
|
|
125
|
-
transactionHash: signingResult.transactionHash,
|
|
126
|
-
error: signingResult.error
|
|
127
|
-
};
|
|
306
|
+
// Use the actual SDK method that handles the complete sign + submit flow
|
|
307
|
+
const submissionResult = await signerSDKRef.current.signAndSubmitPersTransaction(jwt);
|
|
308
|
+
return submissionResult;
|
|
128
309
|
}
|
|
129
310
|
catch (error) {
|
|
130
311
|
console.error('[useTransactionSigner] JWT transaction signing failed:', error);
|
|
131
|
-
|
|
132
|
-
success: false,
|
|
133
|
-
error: `Transaction signing failed: ${error}`
|
|
134
|
-
};
|
|
312
|
+
throw error; // Re-throw to maintain error handling upstream
|
|
135
313
|
}
|
|
136
314
|
}, [isSignerInitialized]);
|
|
137
|
-
/**
|
|
138
|
-
* Manual user authentication (fallback method)
|
|
139
|
-
*/
|
|
140
|
-
const authenticateUser = useCallback(async (identifier) => {
|
|
141
|
-
if (!isSignerInitialized || !signerSDKRef.current) {
|
|
142
|
-
throw new Error('Transaction signer not initialized');
|
|
143
|
-
}
|
|
144
|
-
try {
|
|
145
|
-
console.log('[useTransactionSigner] Manual user authentication:', identifier);
|
|
146
|
-
const user = await signerSDKRef.current.authenticateUser(identifier);
|
|
147
|
-
console.log('[useTransactionSigner] Manual authentication successful');
|
|
148
|
-
return user;
|
|
149
|
-
}
|
|
150
|
-
catch (error) {
|
|
151
|
-
console.error('[useTransactionSigner] Manual authentication failed:', error);
|
|
152
|
-
return null;
|
|
153
|
-
}
|
|
154
|
-
}, [isSignerInitialized]);
|
|
155
|
-
/**
|
|
156
|
-
* Legacy method for backward compatibility
|
|
157
|
-
* @deprecated Use signTransactionWithJWT instead
|
|
158
|
-
*/
|
|
159
|
-
const signTransaction = useCallback(async (jwt) => {
|
|
160
|
-
console.warn('[useTransactionSigner] signTransaction is deprecated, use signTransactionWithJWT');
|
|
161
|
-
return signTransactionWithJWT(jwt);
|
|
162
|
-
}, [signTransactionWithJWT]);
|
|
163
315
|
return {
|
|
164
316
|
/**
|
|
165
|
-
* Sign a blockchain transaction using JWT token
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
*
|
|
170
|
-
* @
|
|
171
|
-
|
|
172
|
-
signTransaction,
|
|
173
|
-
/**
|
|
174
|
-
* Manual user authentication (for advanced use cases)
|
|
317
|
+
* Sign and submit a blockchain transaction using JWT token
|
|
318
|
+
*
|
|
319
|
+
* Main method for executing blockchain transactions. Handles complete flow
|
|
320
|
+
* from authentication to blockchain submission in a single call.
|
|
321
|
+
*
|
|
322
|
+
* @param {string} jwt - JWT token with transaction and user data
|
|
323
|
+
* @returns {Promise<SubmissionResult>} Transaction result with hash and status
|
|
175
324
|
*/
|
|
176
|
-
|
|
325
|
+
signAndSubmitTransactionWithJWT,
|
|
177
326
|
/**
|
|
178
|
-
* Whether the transaction signer has been initialized
|
|
327
|
+
* Whether the transaction signer SDK has been successfully initialized
|
|
328
|
+
*
|
|
329
|
+
* Use this to show loading states while the signer is being set up.
|
|
330
|
+
* When `false`, the signer is still initializing and transactions cannot be processed.
|
|
331
|
+
*
|
|
332
|
+
* @example
|
|
333
|
+
* ```typescript
|
|
334
|
+
* const { isSignerInitialized } = useTransactionSigner();
|
|
335
|
+
*
|
|
336
|
+
* if (!isSignerInitialized) {
|
|
337
|
+
* return <LoadingSpinner text="Initializing signer..." />;
|
|
338
|
+
* }
|
|
339
|
+
* ```
|
|
179
340
|
*/
|
|
180
341
|
isSignerInitialized,
|
|
181
342
|
/**
|
|
182
|
-
* Whether transaction signing is available
|
|
343
|
+
* Whether blockchain transaction signing is fully available
|
|
344
|
+
*
|
|
345
|
+
* This combines multiple checks: SDK availability, initialization status,
|
|
346
|
+
* and configuration validity. Use this to enable/disable transaction buttons.
|
|
347
|
+
*
|
|
348
|
+
* Returns `true` only when:
|
|
349
|
+
* - PERS Signer SDK is installed and available
|
|
350
|
+
* - Signer has been successfully initialized
|
|
351
|
+
* - All required dependencies are loaded
|
|
352
|
+
*
|
|
353
|
+
* @example
|
|
354
|
+
* ```typescript
|
|
355
|
+
* const { isSignerAvailable } = useTransactionSigner();
|
|
356
|
+
*
|
|
357
|
+
* return (
|
|
358
|
+
* <TouchableOpacity
|
|
359
|
+
* disabled={!isSignerAvailable}
|
|
360
|
+
* style={[styles.button, !isSignerAvailable && styles.disabled]}
|
|
361
|
+
* >
|
|
362
|
+
* <Text>{isSignerAvailable ? 'Sign Transaction' : 'Signer Unavailable'}</Text>
|
|
363
|
+
* </TouchableOpacity>
|
|
364
|
+
* );
|
|
365
|
+
* ```
|
|
183
366
|
*/
|
|
184
367
|
isSignerAvailable: isSignerInitialized && !!createPersSignerSDK,
|
|
185
368
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TransactionRequestDTO, TransactionRequestResponseDTO, TransactionDTO } from '@explorins/pers-shared';
|
|
1
|
+
import type { TransactionRequestDTO, TransactionRequestResponseDTO, TransactionDTO, TransactionRole } from '@explorins/pers-shared';
|
|
2
2
|
import type { TransactionPaginationParams } from '@explorins/pers-sdk/transaction';
|
|
3
3
|
/**
|
|
4
4
|
* React hook for transaction operations in the PERS SDK
|
|
@@ -39,7 +39,7 @@ import type { TransactionPaginationParams } from '@explorins/pers-sdk/transactio
|
|
|
39
39
|
export declare const useTransactions: () => {
|
|
40
40
|
createTransaction: (request: TransactionRequestDTO) => Promise<TransactionRequestResponseDTO>;
|
|
41
41
|
getTransactionById: (transactionId: string) => Promise<TransactionDTO | null>;
|
|
42
|
-
getUserTransactionHistory: (
|
|
42
|
+
getUserTransactionHistory: (role?: TransactionRole) => Promise<TransactionDTO[]>;
|
|
43
43
|
getTenantTransactions: () => Promise<TransactionDTO[]>;
|
|
44
44
|
getPaginatedTransactions: (params: TransactionPaginationParams) => Promise<any>;
|
|
45
45
|
exportTransactionsCSV: () => Promise<Blob>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useTransactions.d.ts","sourceRoot":"","sources":["../../src/hooks/useTransactions.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,qBAAqB,EACrB,6BAA6B,EAC7B,cAAc,
|
|
1
|
+
{"version":3,"file":"useTransactions.d.ts","sourceRoot":"","sources":["../../src/hooks/useTransactions.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,qBAAqB,EACrB,6BAA6B,EAC7B,cAAc,EACd,eAAe,EAChB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,iCAAiC,CAAC;AAEnF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,eAAO,MAAM,eAAe;iCA8B4B,qBAAqB,KAAG,QAAQ,6BAA6B,CAAC;wCA8DvD,MAAM,KAAG,QAAQ,cAAc,GAAG,IAAI,CAAC;uCA6BxC,eAAe,KAAG,QAAQ,cAAc,EAAE,CAAC;iCAgBnD,QAAQ,cAAc,EAAE,CAAC;uCAcjB,2BAA2B,KAAG,QAAQ,GAAG,CAAC;iCAelD,QAAQ,IAAI,CAAC;;CAwBlE,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC"}
|
|
@@ -39,7 +39,7 @@ import { useTransactionSigner } from './useTransactionSigner';
|
|
|
39
39
|
*/
|
|
40
40
|
export const useTransactions = () => {
|
|
41
41
|
const { sdk, isInitialized, isAuthenticated } = usePersSDK();
|
|
42
|
-
const {
|
|
42
|
+
const { signAndSubmitTransactionWithJWT, isSignerAvailable } = useTransactionSigner();
|
|
43
43
|
if (!isAuthenticated && isInitialized) {
|
|
44
44
|
console.warn('SDK not authenticated. Some transaction operations may fail.');
|
|
45
45
|
}
|
|
@@ -83,7 +83,7 @@ export const useTransactions = () => {
|
|
|
83
83
|
return result;
|
|
84
84
|
}
|
|
85
85
|
// Automatically sign the transaction using the authToken
|
|
86
|
-
const signingResult = await
|
|
86
|
+
const signingResult = await signAndSubmitTransactionWithJWT(txToken);
|
|
87
87
|
if (signingResult.success) {
|
|
88
88
|
console.log('[useTransactions] Transaction signed successfully:', signingResult.transactionHash);
|
|
89
89
|
// Return the original result - the transaction is now signed and will be processed
|
|
@@ -107,7 +107,7 @@ export const useTransactions = () => {
|
|
|
107
107
|
console.error('Failed to create transaction:', error);
|
|
108
108
|
throw error;
|
|
109
109
|
}
|
|
110
|
-
}, [sdk, isInitialized,
|
|
110
|
+
}, [sdk, isInitialized, signAndSubmitTransactionWithJWT, isSignerAvailable]);
|
|
111
111
|
/**
|
|
112
112
|
* Retrieves a specific transaction by its ID
|
|
113
113
|
*
|
|
@@ -137,25 +137,25 @@ export const useTransactions = () => {
|
|
|
137
137
|
}
|
|
138
138
|
}, [sdk, isInitialized]);
|
|
139
139
|
/**
|
|
140
|
-
* Retrieves transaction history for the authenticated user, filtered by
|
|
140
|
+
* Retrieves transaction history for the authenticated user, filtered by role
|
|
141
141
|
*
|
|
142
|
-
* @param
|
|
142
|
+
* @param role - Optional transaction role filter (TransactionRole.SENDER, TransactionRole.RECIPIENT)
|
|
143
143
|
* @returns Promise resolving to array of user's transactions
|
|
144
144
|
* @throws Error if SDK is not initialized
|
|
145
145
|
*
|
|
146
146
|
* @example
|
|
147
147
|
* ```typescript
|
|
148
148
|
* const { getUserTransactionHistory } = useTransactions();
|
|
149
|
-
* const
|
|
150
|
-
*
|
|
149
|
+
* const sentTransactions = await getUserTransactionHistory(TransactionRole.SENDER);
|
|
150
|
+
* const allTransactions = await getUserTransactionHistory(); // No filter
|
|
151
151
|
* ```
|
|
152
152
|
*/
|
|
153
|
-
const getUserTransactionHistory = useCallback(async (
|
|
153
|
+
const getUserTransactionHistory = useCallback(async (role) => {
|
|
154
154
|
if (!isInitialized || !sdk) {
|
|
155
155
|
throw new Error('SDK not initialized. Call initialize() first.');
|
|
156
156
|
}
|
|
157
157
|
try {
|
|
158
|
-
const result = await sdk.transactions.getUserTransactionHistory(
|
|
158
|
+
const result = await sdk.transactions.getUserTransactionHistory(role);
|
|
159
159
|
console.log('Transaction history fetched successfully:', result);
|
|
160
160
|
return result;
|
|
161
161
|
}
|
|
@@ -170,7 +170,6 @@ export const useTransactions = () => {
|
|
|
170
170
|
}
|
|
171
171
|
try {
|
|
172
172
|
const result = await sdk.transactions.getTenantTransactions();
|
|
173
|
-
console.log('Tenant transactions fetched successfully:', result);
|
|
174
173
|
return result;
|
|
175
174
|
}
|
|
176
175
|
catch (error) {
|