toss-expo-sdk 0.1.2 → 1.0.2
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 +380 -25
- package/lib/module/ble.js +59 -4
- package/lib/module/ble.js.map +1 -1
- package/lib/module/client/BLETransactionHandler.js +277 -0
- package/lib/module/client/BLETransactionHandler.js.map +1 -0
- package/lib/module/client/NonceAccountManager.js +364 -0
- package/lib/module/client/NonceAccountManager.js.map +1 -0
- package/lib/module/client/TossClient.js +1 -1
- package/lib/module/client/TossClient.js.map +1 -1
- package/lib/module/examples/enhancedFeaturesFlow.js +233 -0
- package/lib/module/examples/enhancedFeaturesFlow.js.map +1 -0
- package/lib/module/examples/offlinePaymentFlow.js +27 -27
- package/lib/module/examples/offlinePaymentFlow.js.map +1 -1
- package/lib/module/hooks/useOfflineBLETransactions.js +314 -0
- package/lib/module/hooks/useOfflineBLETransactions.js.map +1 -0
- package/lib/module/index.js +18 -8
- package/lib/module/index.js.map +1 -1
- package/lib/module/intent.js +129 -0
- package/lib/module/intent.js.map +1 -1
- package/lib/module/noise.js +175 -0
- package/lib/module/noise.js.map +1 -1
- package/lib/module/qr.js +2 -2
- package/lib/module/reconciliation.js +155 -0
- package/lib/module/reconciliation.js.map +1 -1
- package/lib/module/services/authService.js +166 -3
- package/lib/module/services/authService.js.map +1 -1
- package/lib/module/storage/secureStorage.js +102 -0
- package/lib/module/storage/secureStorage.js.map +1 -1
- package/lib/module/sync.js +25 -1
- package/lib/module/sync.js.map +1 -1
- package/lib/module/types/nonceAccount.js +2 -0
- package/lib/module/types/nonceAccount.js.map +1 -0
- package/lib/module/types/tossUser.js +16 -1
- package/lib/module/types/tossUser.js.map +1 -1
- package/lib/module/utils/compression.js +210 -0
- package/lib/module/utils/compression.js.map +1 -0
- package/lib/module/wifi.js +311 -0
- package/lib/module/wifi.js.map +1 -0
- package/lib/typescript/src/__tests__/solana-program-simple.test.d.ts +8 -0
- package/lib/typescript/src/__tests__/solana-program-simple.test.d.ts.map +1 -0
- package/lib/typescript/src/ble.d.ts +31 -2
- package/lib/typescript/src/ble.d.ts.map +1 -1
- package/lib/typescript/src/client/BLETransactionHandler.d.ts +98 -0
- package/lib/typescript/src/client/BLETransactionHandler.d.ts.map +1 -0
- package/lib/typescript/src/client/NonceAccountManager.d.ts +82 -0
- package/lib/typescript/src/client/NonceAccountManager.d.ts.map +1 -0
- package/lib/typescript/src/examples/enhancedFeaturesFlow.d.ts +45 -0
- package/lib/typescript/src/examples/enhancedFeaturesFlow.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useOfflineBLETransactions.d.ts +91 -0
- package/lib/typescript/src/hooks/useOfflineBLETransactions.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +11 -4
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/intent.d.ts +15 -0
- package/lib/typescript/src/intent.d.ts.map +1 -1
- package/lib/typescript/src/noise.d.ts +62 -0
- package/lib/typescript/src/noise.d.ts.map +1 -1
- package/lib/typescript/src/reconciliation.d.ts +6 -0
- package/lib/typescript/src/reconciliation.d.ts.map +1 -1
- package/lib/typescript/src/services/authService.d.ts +26 -1
- package/lib/typescript/src/services/authService.d.ts.map +1 -1
- package/lib/typescript/src/storage/secureStorage.d.ts +16 -0
- package/lib/typescript/src/storage/secureStorage.d.ts.map +1 -1
- package/lib/typescript/src/sync.d.ts +6 -1
- package/lib/typescript/src/sync.d.ts.map +1 -1
- package/lib/typescript/src/types/nonceAccount.d.ts +59 -0
- package/lib/typescript/src/types/nonceAccount.d.ts.map +1 -0
- package/lib/typescript/src/types/tossUser.d.ts +16 -0
- package/lib/typescript/src/types/tossUser.d.ts.map +1 -1
- package/lib/typescript/src/utils/compression.d.ts +52 -0
- package/lib/typescript/src/utils/compression.d.ts.map +1 -0
- package/lib/typescript/src/wifi.d.ts +116 -0
- package/lib/typescript/src/wifi.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/__tests__/solana-program-simple.test.ts +256 -0
- package/src/ble.ts +105 -4
- package/src/client/BLETransactionHandler.ts +364 -0
- package/src/client/NonceAccountManager.ts +444 -0
- package/src/client/TossClient.ts +1 -1
- package/src/examples/enhancedFeaturesFlow.ts +272 -0
- package/src/examples/offlinePaymentFlow.ts +27 -27
- package/src/hooks/useOfflineBLETransactions.ts +438 -0
- package/src/index.tsx +52 -6
- package/src/intent.ts +166 -0
- package/src/noise.ts +238 -0
- package/src/qr.tsx +2 -2
- package/src/reconciliation.ts +184 -0
- package/src/services/authService.ts +190 -3
- package/src/storage/secureStorage.ts +138 -0
- package/src/sync.ts +40 -0
- package/src/types/nonceAccount.ts +75 -0
- package/src/types/tossUser.ts +35 -2
- package/src/utils/compression.ts +247 -0
- package/src/wifi.ts +401 -0
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { Device } from 'react-native-ble-plx';
|
|
3
|
+
import { Connection } from '@solana/web3.js';
|
|
4
|
+
import type { SolanaIntent } from '../intent';
|
|
5
|
+
import type {
|
|
6
|
+
OfflineTransaction,
|
|
7
|
+
NonceAccountCacheEntry,
|
|
8
|
+
} from '../types/nonceAccount';
|
|
9
|
+
import type { TossUser } from '../types/tossUser';
|
|
10
|
+
import { BLETransactionHandler } from '../client/BLETransactionHandler';
|
|
11
|
+
import { NonceAccountManager } from '../client/NonceAccountManager';
|
|
12
|
+
import { AuthService } from '../services/authService';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* State for BLE transaction transmission
|
|
16
|
+
*/
|
|
17
|
+
export interface BLETransmissionState {
|
|
18
|
+
isTransmitting: boolean;
|
|
19
|
+
progress: {
|
|
20
|
+
sentFragments: number;
|
|
21
|
+
totalFragments: number;
|
|
22
|
+
messageId?: string;
|
|
23
|
+
};
|
|
24
|
+
error?: string;
|
|
25
|
+
lastSent?: {
|
|
26
|
+
messageId: string;
|
|
27
|
+
timestamp: number;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* State for offline transaction preparation
|
|
33
|
+
*/
|
|
34
|
+
export interface OfflineTransactionState {
|
|
35
|
+
isPreparing: boolean;
|
|
36
|
+
transaction?: OfflineTransaction;
|
|
37
|
+
error?: string;
|
|
38
|
+
isReady: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* useOfflineTransaction Hook
|
|
43
|
+
* Manages offline transaction creation with nonce accounts
|
|
44
|
+
* Handles biometric protection and secure storage
|
|
45
|
+
*/
|
|
46
|
+
export function useOfflineTransaction(user: TossUser, connection: Connection) {
|
|
47
|
+
const [state, setState] = useState<OfflineTransactionState>({
|
|
48
|
+
isPreparing: false,
|
|
49
|
+
isReady: false,
|
|
50
|
+
});
|
|
51
|
+
const nonceManagerRef = useRef<NonceAccountManager | null>(null);
|
|
52
|
+
|
|
53
|
+
// Initialize nonce manager
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
nonceManagerRef.current = new NonceAccountManager(connection);
|
|
56
|
+
|
|
57
|
+
// Cleanup expired cache periodically
|
|
58
|
+
const interval = setInterval(
|
|
59
|
+
() => {
|
|
60
|
+
nonceManagerRef.current?.cleanupExpiredCache();
|
|
61
|
+
},
|
|
62
|
+
5 * 60 * 1000
|
|
63
|
+
); // Every 5 minutes
|
|
64
|
+
|
|
65
|
+
return () => clearInterval(interval);
|
|
66
|
+
}, [connection]);
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Create offline transaction with nonce account
|
|
70
|
+
* Requires biometric verification if enabled
|
|
71
|
+
*/
|
|
72
|
+
const createOfflineTransaction = useCallback(
|
|
73
|
+
async (
|
|
74
|
+
instructions: any[], // TransactionInstruction[]
|
|
75
|
+
metadata?: { description?: string; tags?: string[] }
|
|
76
|
+
): Promise<OfflineTransaction | null> => {
|
|
77
|
+
if (!user.nonceAccount) {
|
|
78
|
+
setState((prev) => ({
|
|
79
|
+
...prev,
|
|
80
|
+
error: 'User does not have nonce account configured',
|
|
81
|
+
}));
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
setState((prev) => ({
|
|
86
|
+
...prev,
|
|
87
|
+
isPreparing: true,
|
|
88
|
+
error: undefined,
|
|
89
|
+
}));
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
// Verify nonce account access (requires biometric if enabled)
|
|
93
|
+
if (user.security.nonceAccountRequiresBiometric) {
|
|
94
|
+
const hasAccess = await AuthService.verifyNonceAccountAccess(
|
|
95
|
+
user.userId
|
|
96
|
+
);
|
|
97
|
+
if (!hasAccess) {
|
|
98
|
+
throw new Error('Biometric verification failed');
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Get cached nonce account or retrieve from storage
|
|
103
|
+
const nonceManager = nonceManagerRef.current!;
|
|
104
|
+
let nonceAccountData = nonceManager.getCachedNonceAccount(user.userId);
|
|
105
|
+
|
|
106
|
+
let nonceAccountInfo: NonceAccountCacheEntry | null = null;
|
|
107
|
+
if (nonceAccountData) {
|
|
108
|
+
nonceAccountInfo = nonceAccountData;
|
|
109
|
+
} else {
|
|
110
|
+
const retrievedInfo = await nonceManager.getNonceAccountSecure(
|
|
111
|
+
user.userId
|
|
112
|
+
);
|
|
113
|
+
if (retrievedInfo) {
|
|
114
|
+
nonceAccountInfo = nonceManager.getCachedNonceAccount(user.userId);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (!nonceAccountInfo) {
|
|
119
|
+
throw new Error('Failed to retrieve nonce account information');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Validate nonce account
|
|
123
|
+
if (!nonceManager.isNonceAccountValid(nonceAccountInfo.accountInfo)) {
|
|
124
|
+
throw new Error('Nonce account is no longer valid');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Prepare offline transaction
|
|
128
|
+
const transaction = await nonceManager.prepareOfflineTransaction(
|
|
129
|
+
user,
|
|
130
|
+
instructions,
|
|
131
|
+
nonceAccountInfo.accountInfo
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
transaction.metadata = metadata || {};
|
|
135
|
+
|
|
136
|
+
setState((prev) => ({
|
|
137
|
+
...prev,
|
|
138
|
+
transaction,
|
|
139
|
+
isReady: true,
|
|
140
|
+
isPreparing: false,
|
|
141
|
+
}));
|
|
142
|
+
|
|
143
|
+
return transaction;
|
|
144
|
+
} catch (error) {
|
|
145
|
+
const errorMessage =
|
|
146
|
+
error instanceof Error ? error.message : String(error);
|
|
147
|
+
setState((prev) => ({
|
|
148
|
+
...prev,
|
|
149
|
+
error: errorMessage,
|
|
150
|
+
isPreparing: false,
|
|
151
|
+
isReady: false,
|
|
152
|
+
}));
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
[user]
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Clear current offline transaction
|
|
161
|
+
*/
|
|
162
|
+
const clearTransaction = useCallback(() => {
|
|
163
|
+
setState({
|
|
164
|
+
isPreparing: false,
|
|
165
|
+
isReady: false,
|
|
166
|
+
});
|
|
167
|
+
}, []);
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
...state,
|
|
171
|
+
createOfflineTransaction,
|
|
172
|
+
clearTransaction,
|
|
173
|
+
nonceManager: nonceManagerRef.current,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* useBLETransactionTransmission Hook
|
|
179
|
+
* Handles secure BLE transmission of fragmented transactions
|
|
180
|
+
* with Noise Protocol encryption
|
|
181
|
+
*/
|
|
182
|
+
export function useBLETransactionTransmission(
|
|
183
|
+
platform: 'android' | 'ios' = 'android'
|
|
184
|
+
) {
|
|
185
|
+
const [state, setState] = useState<BLETransmissionState>({
|
|
186
|
+
isTransmitting: false,
|
|
187
|
+
progress: {
|
|
188
|
+
sentFragments: 0,
|
|
189
|
+
totalFragments: 0,
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
const bleHandlerRef = useRef(new BLETransactionHandler(platform));
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Send transaction over BLE with fragmentation
|
|
197
|
+
*/
|
|
198
|
+
const sendTransactionBLE = useCallback(
|
|
199
|
+
async (
|
|
200
|
+
device: Device,
|
|
201
|
+
transaction: OfflineTransaction | SolanaIntent,
|
|
202
|
+
sendFn: (
|
|
203
|
+
deviceId: string,
|
|
204
|
+
characteristicUUID: string,
|
|
205
|
+
data: Buffer
|
|
206
|
+
) => Promise<void>,
|
|
207
|
+
noiseEncryptFn?: (data: Uint8Array) => Promise<any>,
|
|
208
|
+
isIntent: boolean = false
|
|
209
|
+
): Promise<boolean> => {
|
|
210
|
+
setState((prev) => ({
|
|
211
|
+
...prev,
|
|
212
|
+
isTransmitting: true,
|
|
213
|
+
error: undefined,
|
|
214
|
+
}));
|
|
215
|
+
|
|
216
|
+
try {
|
|
217
|
+
const bleHandler = bleHandlerRef.current;
|
|
218
|
+
const result = await bleHandler.sendFragmentedTransactionBLE(
|
|
219
|
+
device,
|
|
220
|
+
transaction,
|
|
221
|
+
sendFn,
|
|
222
|
+
noiseEncryptFn,
|
|
223
|
+
isIntent
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
if (!result.success) {
|
|
227
|
+
const failedCount = result.failedFragments.length;
|
|
228
|
+
throw new Error(
|
|
229
|
+
`Failed to send ${failedCount} fragment(s): ${result.failedFragments.join(', ')}`
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
setState((prev) => ({
|
|
234
|
+
...prev,
|
|
235
|
+
isTransmitting: false,
|
|
236
|
+
progress: {
|
|
237
|
+
sentFragments: result.sentFragments,
|
|
238
|
+
totalFragments:
|
|
239
|
+
result.sentFragments + result.failedFragments.length,
|
|
240
|
+
messageId: result.messageId,
|
|
241
|
+
},
|
|
242
|
+
lastSent: {
|
|
243
|
+
messageId: result.messageId,
|
|
244
|
+
timestamp: Date.now(),
|
|
245
|
+
},
|
|
246
|
+
}));
|
|
247
|
+
|
|
248
|
+
return true;
|
|
249
|
+
} catch (error) {
|
|
250
|
+
const errorMessage =
|
|
251
|
+
error instanceof Error ? error.message : String(error);
|
|
252
|
+
setState((prev) => ({
|
|
253
|
+
...prev,
|
|
254
|
+
isTransmitting: false,
|
|
255
|
+
error: errorMessage,
|
|
256
|
+
}));
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
[]
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Receive fragmented transaction
|
|
265
|
+
*/
|
|
266
|
+
const receiveTransactionFragment = useCallback(
|
|
267
|
+
async (
|
|
268
|
+
fragment: any, // BLEFragment
|
|
269
|
+
noiseDecryptFn?: (encrypted: any) => Promise<Uint8Array>
|
|
270
|
+
): Promise<{
|
|
271
|
+
complete: boolean;
|
|
272
|
+
transaction?: OfflineTransaction | SolanaIntent;
|
|
273
|
+
progress: { received: number; total: number };
|
|
274
|
+
}> => {
|
|
275
|
+
try {
|
|
276
|
+
const bleHandler = bleHandlerRef.current;
|
|
277
|
+
const result = await bleHandler.receiveFragmentedMessage(
|
|
278
|
+
fragment,
|
|
279
|
+
noiseDecryptFn
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
setState((prev) => ({
|
|
283
|
+
...prev,
|
|
284
|
+
progress: {
|
|
285
|
+
sentFragments: result.progress.received,
|
|
286
|
+
totalFragments: result.progress.total,
|
|
287
|
+
messageId: fragment.messageId,
|
|
288
|
+
},
|
|
289
|
+
}));
|
|
290
|
+
|
|
291
|
+
return result;
|
|
292
|
+
} catch (error) {
|
|
293
|
+
const errorMessage =
|
|
294
|
+
error instanceof Error ? error.message : String(error);
|
|
295
|
+
setState((prev) => ({
|
|
296
|
+
...prev,
|
|
297
|
+
error: errorMessage,
|
|
298
|
+
}));
|
|
299
|
+
|
|
300
|
+
return {
|
|
301
|
+
complete: false,
|
|
302
|
+
progress: { received: 0, total: 0 },
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
[]
|
|
307
|
+
);
|
|
308
|
+
|
|
309
|
+
const getMTUConfig = useCallback(() => {
|
|
310
|
+
return bleHandlerRef.current.getMTUConfig();
|
|
311
|
+
}, []);
|
|
312
|
+
|
|
313
|
+
const setMTUConfig = useCallback((config: Partial<any>) => {
|
|
314
|
+
bleHandlerRef.current.setMTUConfig(config);
|
|
315
|
+
}, []);
|
|
316
|
+
|
|
317
|
+
return {
|
|
318
|
+
...state,
|
|
319
|
+
sendTransactionBLE,
|
|
320
|
+
receiveTransactionFragment,
|
|
321
|
+
getMTUConfig,
|
|
322
|
+
setMTUConfig,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* useNonceAccountManagement Hook
|
|
328
|
+
* Manages nonce account lifecycle: creation, renewal, revocation
|
|
329
|
+
*/
|
|
330
|
+
export function useNonceAccountManagement(
|
|
331
|
+
user: TossUser,
|
|
332
|
+
connection: Connection
|
|
333
|
+
) {
|
|
334
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
335
|
+
const [error, setError] = useState<string | undefined>();
|
|
336
|
+
const nonceManagerRef = useRef(new NonceAccountManager(connection));
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Create nonce account with biometric protection
|
|
340
|
+
*/
|
|
341
|
+
const createNonceAccount = useCallback(
|
|
342
|
+
async (userKeypair: any) => {
|
|
343
|
+
setIsLoading(true);
|
|
344
|
+
setError(undefined);
|
|
345
|
+
|
|
346
|
+
try {
|
|
347
|
+
const updatedUser = await AuthService.createSecureNonceAccount(
|
|
348
|
+
user,
|
|
349
|
+
connection,
|
|
350
|
+
userKeypair
|
|
351
|
+
);
|
|
352
|
+
|
|
353
|
+
return updatedUser;
|
|
354
|
+
} catch (err) {
|
|
355
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
356
|
+
setError(errorMessage);
|
|
357
|
+
return null;
|
|
358
|
+
} finally {
|
|
359
|
+
setIsLoading(false);
|
|
360
|
+
}
|
|
361
|
+
},
|
|
362
|
+
[user, connection]
|
|
363
|
+
);
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Renew nonce account (refresh from blockchain)
|
|
367
|
+
*/
|
|
368
|
+
const renewNonceAccount = useCallback(async () => {
|
|
369
|
+
if (!user.nonceAccount) {
|
|
370
|
+
setError('No nonce account to renew');
|
|
371
|
+
return null;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
setIsLoading(true);
|
|
375
|
+
setError(undefined);
|
|
376
|
+
|
|
377
|
+
try {
|
|
378
|
+
const updated = await nonceManagerRef.current.renewNonceAccount(
|
|
379
|
+
user.userId,
|
|
380
|
+
user.nonceAccount.address
|
|
381
|
+
);
|
|
382
|
+
|
|
383
|
+
return updated;
|
|
384
|
+
} catch (err) {
|
|
385
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
386
|
+
setError(errorMessage);
|
|
387
|
+
return null;
|
|
388
|
+
} finally {
|
|
389
|
+
setIsLoading(false);
|
|
390
|
+
}
|
|
391
|
+
}, [user.userId, user.nonceAccount]);
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Revoke nonce account
|
|
395
|
+
*/
|
|
396
|
+
const revokeNonceAccount = useCallback(async () => {
|
|
397
|
+
setIsLoading(true);
|
|
398
|
+
setError(undefined);
|
|
399
|
+
|
|
400
|
+
try {
|
|
401
|
+
const updatedUser = await AuthService.revokeNonceAccount(
|
|
402
|
+
user.userId,
|
|
403
|
+
user
|
|
404
|
+
);
|
|
405
|
+
|
|
406
|
+
return updatedUser;
|
|
407
|
+
} catch (err) {
|
|
408
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
409
|
+
setError(errorMessage);
|
|
410
|
+
return null;
|
|
411
|
+
} finally {
|
|
412
|
+
setIsLoading(false);
|
|
413
|
+
}
|
|
414
|
+
}, [user]);
|
|
415
|
+
|
|
416
|
+
const isNonceAccountValid = useCallback(() => {
|
|
417
|
+
if (!user.nonceAccount) {
|
|
418
|
+
return false;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
const cached = nonceManagerRef.current.getCachedNonceAccount(user.userId);
|
|
422
|
+
if (cached) {
|
|
423
|
+
return nonceManagerRef.current.isNonceAccountValid(cached.accountInfo);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
return user.nonceAccount.status === 'active';
|
|
427
|
+
}, [user.userId, user.nonceAccount]);
|
|
428
|
+
|
|
429
|
+
return {
|
|
430
|
+
isLoading,
|
|
431
|
+
error,
|
|
432
|
+
createNonceAccount,
|
|
433
|
+
renewNonceAccount,
|
|
434
|
+
revokeNonceAccount,
|
|
435
|
+
isNonceAccountValid,
|
|
436
|
+
hasNonceAccount: !!user.nonceAccount,
|
|
437
|
+
};
|
|
438
|
+
}
|
package/src/index.tsx
CHANGED
|
@@ -3,10 +3,39 @@ export {
|
|
|
3
3
|
createIntent,
|
|
4
4
|
createUserIntent,
|
|
5
5
|
createSignedIntent,
|
|
6
|
+
createOfflineIntent,
|
|
6
7
|
type SolanaIntent,
|
|
7
8
|
type IntentStatus,
|
|
8
9
|
} from './intent';
|
|
9
10
|
|
|
11
|
+
// Nonce Account Management (for offline transactions)
|
|
12
|
+
export { NonceAccountManager } from './client/NonceAccountManager';
|
|
13
|
+
export type {
|
|
14
|
+
NonceAccountInfo,
|
|
15
|
+
NonceAccountCacheEntry,
|
|
16
|
+
CreateNonceAccountOptions,
|
|
17
|
+
OfflineTransaction,
|
|
18
|
+
} from './types/nonceAccount';
|
|
19
|
+
|
|
20
|
+
// BLE Transaction Handling (fragmentation & Noise encryption)
|
|
21
|
+
export { BLETransactionHandler } from './client/BLETransactionHandler';
|
|
22
|
+
export type {
|
|
23
|
+
BLEFragment,
|
|
24
|
+
EncryptedBLEMessage,
|
|
25
|
+
BLEMTUConfig,
|
|
26
|
+
} from './client/BLETransactionHandler';
|
|
27
|
+
|
|
28
|
+
// Custom Hooks for Offline BLE Transactions
|
|
29
|
+
export {
|
|
30
|
+
useOfflineTransaction,
|
|
31
|
+
useBLETransactionTransmission,
|
|
32
|
+
useNonceAccountManagement,
|
|
33
|
+
} from './hooks/useOfflineBLETransactions';
|
|
34
|
+
export type {
|
|
35
|
+
BLETransmissionState,
|
|
36
|
+
OfflineTransactionState,
|
|
37
|
+
} from './hooks/useOfflineBLETransactions';
|
|
38
|
+
|
|
10
39
|
// Intent management
|
|
11
40
|
export {
|
|
12
41
|
verifyIntentSignature,
|
|
@@ -24,8 +53,15 @@ export {
|
|
|
24
53
|
clearPendingIntents,
|
|
25
54
|
} from './storage';
|
|
26
55
|
|
|
27
|
-
// Transport methods
|
|
28
|
-
export {
|
|
56
|
+
// Transport methods (enhanced with fragmentation)
|
|
57
|
+
export {
|
|
58
|
+
startTossScan,
|
|
59
|
+
requestBLEPermissions,
|
|
60
|
+
sendOfflineTransactionFragmented,
|
|
61
|
+
receiveOfflineTransactionFragment,
|
|
62
|
+
getBLEMTUConfig,
|
|
63
|
+
setBLEMTUConfig,
|
|
64
|
+
} from './ble';
|
|
29
65
|
export { initNFC, readNFCUser, writeUserToNFC, writeIntentToNFC } from './nfc';
|
|
30
66
|
export { QRScanner } from './qr';
|
|
31
67
|
|
|
@@ -34,10 +70,8 @@ export { TossClient, type TossConfig } from './client/TossClient';
|
|
|
34
70
|
export type { TossUser } from './types/tossUser';
|
|
35
71
|
export { WalletProvider, useWallet } from './contexts/WalletContext';
|
|
36
72
|
|
|
37
|
-
//
|
|
38
|
-
|
|
39
|
-
export const createClient = TossClient.createClient;
|
|
40
|
-
|
|
73
|
+
// Authentication Service (enhanced with nonce accounts)
|
|
74
|
+
export { AuthService } from './services/authService';
|
|
41
75
|
// Sync and settlement
|
|
42
76
|
export { syncToChain, checkSyncStatus, type SyncResult } from './sync';
|
|
43
77
|
|
|
@@ -67,3 +101,15 @@ export {
|
|
|
67
101
|
type IntentExchangeRequest,
|
|
68
102
|
type IntentExchangeResponse,
|
|
69
103
|
} from './discovery';
|
|
104
|
+
|
|
105
|
+
// Compression utilities
|
|
106
|
+
export {
|
|
107
|
+
compressMetadata,
|
|
108
|
+
decompressMetadata,
|
|
109
|
+
compressIntentMetadata,
|
|
110
|
+
decompressIntentMetadata,
|
|
111
|
+
estimateCompressionSavings,
|
|
112
|
+
} from './utils/compression';
|
|
113
|
+
|
|
114
|
+
// WiFi Direct transport
|
|
115
|
+
export { WiFiDirectTransport, SmartTransportSelector } from './wifi';
|